[
  {
    "path": ".clang-format",
    "content": "BasedOnStyle: Google\nUseTab: Never\nIndentWidth: 4\nBreakBeforeBraces: Allman\nAllowShortIfStatementsOnASingleLine: false\nIndentCaseLabels: false\nColumnLimit: 99\nIndentAccessModifiers: false\nAccessModifierOffset: -4\n"
  },
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs     diff=csharp\n\n# Standard to msysgit\n*.doc\t diff=astextplain\n*.DOC\t diff=astextplain\n*.docx diff=astextplain\n*.DOCX diff=astextplain\n*.dot  diff=astextplain\n*.DOT  diff=astextplain\n*.pdf  diff=astextplain\n*.PDF\t diff=astextplain\n*.rtf\t diff=astextplain\n*.RTF\t diff=astextplain\n"
  },
  {
    "path": ".github/workflows/msbuild.yml",
    "content": "# This workflow uses actions that are not certified by GitHub.\n# They are provided by a third-party and are governed by\n# separate terms of service, privacy policy, and support\n# documentation.\n\nname: MSBuild\n\non:\n  workflow_dispatch:\n\nenv:\n  # Path to the solution file relative to the root of the project.\n  SOLUTION_FILE_PATH: ./Player.sln\n\n  # Configuration type to build.\n  # You can convert this to a build matrix if you need coverage of multiple configuration types.\n  # https://docs.github.com/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix\n  BUILD_CONFIGURATION: Release\n  # https://learn.microsoft.com/en-us/vcpkg/consume/binary-caching-github-actions-cache?source=recommendations\n  VCPKG_BINARY_SOURCES: \"clear;x-gha,readwrite\"\n\n\njobs:\n  build:\n    runs-on: windows-latest\n\n    strategy:\n      matrix:\n        platform: [x86, x64]\n\n    steps:\n    - uses: actions/checkout@v4\n      with:\n        submodules: true  # Ensure submodules are checked out\n\n    - name: Create Directory.Build.props\n      run: |\n        $content = \"<Project><PropertyGroup><WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion><TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion><PlatformToolset>v143</PlatformToolset></PropertyGroup></Project>\"\n        $filePath = \"./Directory.Build.props\"\n        Set-Content -Path $filePath -Value $content\n\n    - name: Add MSBuild to PATH\n      id: setup-msbuild\n      uses: microsoft/setup-msbuild@v2\n\n    - name: Export GitHub Actions cache environment variables\n      uses: actions/github-script@v7\n      with:\n        script: |\n          core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || '');\n          core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || '');\n\n    - name: Install vcpkg\n      run: |\n          git clone https://github.com/microsoft/vcpkg.git\n          cd vcpkg\n          # see https://github.com/microsoft/vcpkg/issues/43802\n          #git checkout 62aa44929954469878eb8fc562af706a8f5615a5\n          ./bootstrap-vcpkg.bat\n          ./vcpkg integrate install\n\n    - name: Install dependencies\n      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\n\n    - name: Restore NuGet packages\n      working-directory: ${{env.GITHUB_WORKSPACE}}\n      run: nuget restore ${{env.SOLUTION_FILE_PATH}}\n\n    - name: Find OpenCV Header\n      run: |\n        $opencvHeader = Get-ChildItem -Path \"./vcpkg/\" -Recurse -Filter \"opencv.hpp\" | Where-Object { $_.FullName -match \"opencv2\\\\opencv.hpp\" }\n        if ($opencvHeader) {\n        Write-Output \"Found OpenCV header at: $($opencvHeader.FullName)\"\n        } else {\n        Write-Error \"OpenCV header not found\"\n        }\n\n    - name: Build\n      working-directory: ${{env.GITHUB_WORKSPACE}}\n      # Add additional options to the MSBuild command line here (like platform or verbosity level).\n      # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference\n      run: msbuild /m /p:Configuration=${{env.BUILD_CONFIGURATION}} /p:Platform=${{matrix.platform == 'x86' && 'Win32' || matrix.platform}} \"/t:Player;ToUTF8\" ${{env.SOLUTION_FILE_PATH}}\n\n    - name: Complete build artifacts\n      run: |\n        $CRT_path = Get-ChildItem -Path \"${{ steps.setup-msbuild.outputs.msbuildPath }}/../../../VC/Redist/MSVC/*/${{matrix.platform}}/Microsoft.VC143.CRT\" | Select-Object -First 1 -ExpandProperty FullName\n        $MFC_path = Get-ChildItem -Path \"${{ steps.setup-msbuild.outputs.msbuildPath }}/../../../VC/Redist/MSVC/*/${{matrix.platform}}/Microsoft.VC143.MFC\" | Select-Object -First 1 -ExpandProperty FullName\n        Write-Output \"CRT PATH=$CRT_path\"\n        Write-Output \"MFC PATH=$MFC_path\"\n        ./vcpkg/scripts/buildsystems/msbuild/applocal.ps1 -targetBinary \"./${{matrix.platform == 'x64' && matrix.platform || ''}}/Release/Player.exe\" -installedDir \"$CRT_path\" -OutVariable out\n        ./vcpkg/scripts/buildsystems/msbuild/applocal.ps1 -targetBinary \"./${{matrix.platform == 'x64' && matrix.platform || ''}}/Release/Player.exe\" -installedDir \"$MFC_path\" -OutVariable out\n\n    - name: Copy FFmpeg tools\n      run: Copy-Item -Path \"./vcpkg/installed/${{matrix.platform}}-windows/tools/ffmpeg/*\" -Destination \"./${{matrix.platform == 'x64' && matrix.platform || ''}}/Release/\" -Recurse -Force -ErrorAction SilentlyContinue\n\n    - name: Delete .pdb files\n      run: Remove-Item -Path \"./${{matrix.platform == 'x64' && matrix.platform || ''}}/Release/*.pdb\" -Force\n\n    - name: Delete .lib files\n      run: Remove-Item -Path \"./${{matrix.platform == 'x64' && matrix.platform || ''}}/Release/*.lib\" -Force\n\n    - name: Upload build artifacts\n      uses: actions/upload-artifact@v4\n      with:\n          name: build-artifacts-${{matrix.platform}}\n          path: ./${{matrix.platform == 'x64' && matrix.platform || ''}}/Release\n"
  },
  {
    "path": ".gitignore",
    "content": "#################\n## Eclipse\n#################\n\n*.pydevproject\n.project\n.metadata\nbin/\ntmp/\n*.tmp\n*.bak\n*.swp\n*~.nib\nlocal.properties\n.classpath\n.settings/\n.loadpath\n\n# External tool builders\n.externalToolBuilders/\n\n# Locally stored \"Eclipse launch configurations\"\n*.launch\n\n# CDT-specific\n.cproject\n\n# PDT-specific\n.buildpath\n\n\n#################\n## Visual Studio\n#################\n\n## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.sln.docstates\n\n# Build results\n\n[Dd]ebug/\n[Rr]elease/\nx64/\nbuild/\n[Bb]in/\n[Oo]bj/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n*_i.c\n*_p.c\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.log\n*.scc\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opensdf\n*.sdf\n*.cachefile\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n*.ncrunch*\n.*crunch*.local.xml\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.Publish.xml\n*.pubxml\n*.publishproj\n\n# NuGet Packages Directory\n## TODO: If you have NuGet Package Restore enabled, uncomment the next line\n#packages/\n\n# Windows Azure Build Output\ncsx\n*.build.csdef\n\n# Windows Store app package directory\nAppPackages/\n\n# Others\nsql/\n*.Cache\nClientBin/\n[Ss]tyle[Cc]op.*\n~$*\n*~\n*.dbmdl\n*.[Pp]ublish.xml\n*.pfx\n*.publishsettings\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file to a newer\n# Visual Studio version. Backup files are not needed, because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\nApp_Data/*.mdf\nApp_Data/*.ldf\n\n#############\n## Windows detritus\n#############\n\n# Windows image file caches\nThumbs.db\nehthumbs.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Mac crap\n.DS_Store\n\n\n#############\n## Python\n#############\n\n*.py[cod]\n\n# Packages\n*.egg\n*.egg-info\ndist/\nbuild/\neggs/\nparts/\nvar/\nsdist/\ndevelop-eggs/\n.installed.cfg\n\n# Installer logs\npip-log.txt\n\n# Unit test / coverage reports\n.coverage\n.tox\n\n#Translations\n*.mo\n\n#Mr Developer\n.mr.developer.cfg\n\nipch/\nffmpeg/\nPlayer/I420Effect_PS.h\nPlayer.VC.db\nPlayer.VC.VC.opendb\n*.diagsession\n\nCMakeLists.txt.user*\n\n.clang-tidy\n\n.vs/\n\nPlayer/version.h\n\nbuild-*/\n\nDirectory.Build.props\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"Anime4KCPP\"]\n\tpath = Anime4KCPP\n\turl = https://github.com/TianZerL/Anime4KCPP.git\n"
  },
  {
    "path": "Anime4KCPPCore.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{632353E4-4856-38F9-9E74-ED41BD99D7E5}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <Platform>Win32</Platform>\n    <ProjectName>Anime4KCPPCore</ProjectName>\n    <VCProjectUpgraderObjectName>NoUpgrade</VCProjectUpgraderObjectName>\n    <VcpkgEnabled>true</VcpkgEnabled>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <CharacterSet>MultiByte</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\">\n    <Import Project=\"do_not_import_user.props\" Condition=\"exists('do_not_import_user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup>\n    <_ProjectFileVersion>10.0.20506.1</_ProjectFileVersion>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Anime4KCPP\\build\\bin\\Debug\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Anime4KCPPCore.dir\\Debug\\</IntDir>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Anime4KCPPCore</TargetName>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Anime4KCPPCore</TargetName>\n    <TargetExt Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">.lib</TargetExt>\n    <TargetExt Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">.lib</TargetExt>\n    <OutDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Anime4KCPP\\build\\bin\\Release\\</OutDir>\n    <IntDir Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Anime4KCPPCore.dir\\Release\\</IntDir>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Anime4KCPPCore</TargetName>\n    <TargetName Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Anime4KCPPCore</TargetName>\n    <TargetExt Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">.lib</TargetExt>\n    <TargetExt Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">.lib</TargetExt>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>Anime4KCPP\\core\\include;core;ThirdParty\\include\\opencl;$(INTELOCLSDKROOT)\\include;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <ExceptionHandling>Sync</ExceptionHandling>\n      <InlineFunctionExpansion>Disabled</InlineFunctionExpansion>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <Optimization>Disabled</Optimization>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <RuntimeTypeInfo>true</RuntimeTypeInfo>\n      <SuppressStartupBanner>\n      </SuppressStartupBanner>\n      <UseFullPaths>false</UseFullPaths>\n      <WarningLevel>Level3</WarningLevel>\n      <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_WINDOWS;ENABLE_OPENCL;ENABLE_VIDEO;ENABLE_PREVIEW_GUI;ENABLE_IMAGE_IO;ANIME4KCPP_CORE_PARALLEL_LIBRARY=\"PPL\";ANIME4KCPP_CORE_COMPILER=\"MSVC\";ANIME4KCPP_CORE_BUILD_DATE=\"2021-10-01\";ANIME4KCPP_CORE_VERSION=\"2.6.0\";ANIME4KCPP_CORE_VERSION_MAJOR=2;ANIME4KCPP_CORE_VERSION_MINOR=6;ANIME4KCPP_CORE_VERSION_PATCH=0;ANIME4KCPP_CORE_VERSION_STATUS=\"dev\";BUILT_IN_KERNEL;USE_PPL;CMAKE_INTDIR=\"Debug\"</PreprocessorDefinitions>\n      <ObjectFileName>$(IntDir)</ObjectFileName>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_DEBUG;_WINDOWS;ENABLE_OPENCL;ENABLE_VIDEO;ENABLE_PREVIEW_GUI;ENABLE_IMAGE_IO;ANIME4KCPP_CORE_PARALLEL_LIBRARY=\\\"PPL\\\";ANIME4KCPP_CORE_COMPILER=\\\"MSVC\\\";ANIME4KCPP_CORE_BUILD_DATE=\\\"2021-10-01\\\";ANIME4KCPP_CORE_VERSION=\\\"2.6.0\\\";ANIME4KCPP_CORE_VERSION_MAJOR=2;ANIME4KCPP_CORE_VERSION_MINOR=6;ANIME4KCPP_CORE_VERSION_PATCH=0;ANIME4KCPP_CORE_VERSION_STATUS=\\\"dev\\\";BUILT_IN_KERNEL;USE_PPL;CMAKE_INTDIR=\\\"Debug\\\"</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>Anime4KCPP\\core\\include;Anime4KCPP\\build\\core;Anime4KCPP\\ThirdParty\\include\\opencl;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;$(INTELOCLSDKROOT)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <Midl>\n      <AdditionalIncludeDirectories>Anime4KCPP\\core\\include;Anime4KCPP\\build\\core;Anime4KCPP\\ThirdParty\\include\\opencl;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;$(INTELOCLSDKROOT)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>\n      <HeaderFileName>%(Filename).h</HeaderFileName>\n      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>\n      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>\n      <ProxyFileName>%(Filename)_p.c</ProxyFileName>\n    </Midl>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>Anime4KCPP\\core\\include;core;ThirdParty\\include\\opencl;$(INTELOCLSDKROOT)\\include;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\n      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <ExceptionHandling>Sync</ExceptionHandling>\n      <InlineFunctionExpansion>Disabled</InlineFunctionExpansion>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <Optimization>Disabled</Optimization>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>\n      <RuntimeTypeInfo>true</RuntimeTypeInfo>\n      <SuppressStartupBanner>\n      </SuppressStartupBanner>\n      <UseFullPaths>false</UseFullPaths>\n      <WarningLevel>Level3</WarningLevel>\n      <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_WINDOWS;ENABLE_OPENCL;ENABLE_VIDEO;ENABLE_PREVIEW_GUI;ENABLE_IMAGE_IO;ANIME4KCPP_CORE_PARALLEL_LIBRARY=\"PPL\";ANIME4KCPP_CORE_COMPILER=\"MSVC\";ANIME4KCPP_CORE_BUILD_DATE=\"2021-10-01\";ANIME4KCPP_CORE_VERSION=\"2.6.0\";ANIME4KCPP_CORE_VERSION_MAJOR=2;ANIME4KCPP_CORE_VERSION_MINOR=6;ANIME4KCPP_CORE_VERSION_PATCH=0;ANIME4KCPP_CORE_VERSION_STATUS=\"dev\";BUILT_IN_KERNEL;USE_PPL;CMAKE_INTDIR=\"Debug\"</PreprocessorDefinitions>\n      <ObjectFileName>$(IntDir)</ObjectFileName>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_DEBUG;_WINDOWS;ENABLE_OPENCL;ENABLE_VIDEO;ENABLE_PREVIEW_GUI;ENABLE_IMAGE_IO;ANIME4KCPP_CORE_PARALLEL_LIBRARY=\\\"PPL\\\";ANIME4KCPP_CORE_COMPILER=\\\"MSVC\\\";ANIME4KCPP_CORE_BUILD_DATE=\\\"2021-10-01\\\";ANIME4KCPP_CORE_VERSION=\\\"2.6.0\\\";ANIME4KCPP_CORE_VERSION_MAJOR=2;ANIME4KCPP_CORE_VERSION_MINOR=6;ANIME4KCPP_CORE_VERSION_PATCH=0;ANIME4KCPP_CORE_VERSION_STATUS=\\\"dev\\\";BUILT_IN_KERNEL;USE_PPL;CMAKE_INTDIR=\\\"Debug\\\"</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>Anime4KCPP\\core\\include;Anime4KCPP\\build\\core;Anime4KCPP\\ThirdParty\\include\\opencl;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;$(INTELOCLSDKROOT)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <Midl>\n      <AdditionalIncludeDirectories>Anime4KCPP\\core\\include;Anime4KCPP\\build\\core;Anime4KCPP\\ThirdParty\\include\\opencl;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;$(INTELOCLSDKROOT)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>\n      <HeaderFileName>%(Filename).h</HeaderFileName>\n      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>\n      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>\n      <ProxyFileName>%(Filename)_p.c</ProxyFileName>\n    </Midl>\n    <Lib>\n      <AdditionalOptions>\n      </AdditionalOptions>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>Anime4KCPP\\core\\include;core;ThirdParty\\include\\opencl;$(INTELOCLSDKROOT)\\include;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <ExceptionHandling>Sync</ExceptionHandling>\n      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <Optimization>MaxSpeed</Optimization>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <RuntimeTypeInfo>true</RuntimeTypeInfo>\n      <SuppressStartupBanner>\n      </SuppressStartupBanner>\n      <UseFullPaths>false</UseFullPaths>\n      <WarningLevel>Level3</WarningLevel>\n      <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_WINDOWS;NDEBUG;ENABLE_OPENCL;ENABLE_VIDEO;ENABLE_PREVIEW_GUI;ENABLE_IMAGE_IO;ANIME4KCPP_CORE_PARALLEL_LIBRARY=\"PPL\";ANIME4KCPP_CORE_COMPILER=\"MSVC\";ANIME4KCPP_CORE_BUILD_DATE=\"2021-10-01\";ANIME4KCPP_CORE_VERSION=\"2.6.0\";ANIME4KCPP_CORE_VERSION_MAJOR=2;ANIME4KCPP_CORE_VERSION_MINOR=6;ANIME4KCPP_CORE_VERSION_PATCH=0;ANIME4KCPP_CORE_VERSION_STATUS=\"dev\";BUILT_IN_KERNEL;USE_PPL;CMAKE_INTDIR=\"Release\"</PreprocessorDefinitions>\n      <ObjectFileName>$(IntDir)</ObjectFileName>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_WINDOWS;NDEBUG;ENABLE_OPENCL;ENABLE_VIDEO;ENABLE_PREVIEW_GUI;ENABLE_IMAGE_IO;ANIME4KCPP_CORE_PARALLEL_LIBRARY=\\\"PPL\\\";ANIME4KCPP_CORE_COMPILER=\\\"MSVC\\\";ANIME4KCPP_CORE_BUILD_DATE=\\\"2021-10-01\\\";ANIME4KCPP_CORE_VERSION=\\\"2.6.0\\\";ANIME4KCPP_CORE_VERSION_MAJOR=2;ANIME4KCPP_CORE_VERSION_MINOR=6;ANIME4KCPP_CORE_VERSION_PATCH=0;ANIME4KCPP_CORE_VERSION_STATUS=\\\"dev\\\";BUILT_IN_KERNEL;USE_PPL;CMAKE_INTDIR=\\\"Release\\\"</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>Anime4KCPP\\core\\include;Anime4KCPP\\build\\core;Anime4KCPP\\ThirdParty\\include\\opencl;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;$(INTELOCLSDKROOT)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <Midl>\n      <AdditionalIncludeDirectories>Anime4KCPP\\core\\include;Anime4KCPP\\build\\core;Anime4KCPP\\ThirdParty\\include\\opencl;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;$(INTELOCLSDKROOT)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>\n      <HeaderFileName>%(Filename).h</HeaderFileName>\n      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>\n      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>\n      <ProxyFileName>%(Filename)_p.c</ProxyFileName>\n    </Midl>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <AdditionalIncludeDirectories>Anime4KCPP\\core\\include;core;ThirdParty\\include\\opencl;$(INTELOCLSDKROOT)\\include;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>\n      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>\n      <ExceptionHandling>Sync</ExceptionHandling>\n      <InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n      <Optimization>MaxSpeed</Optimization>\n      <PrecompiledHeader>NotUsing</PrecompiledHeader>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n      <RuntimeTypeInfo>true</RuntimeTypeInfo>\n      <SuppressStartupBanner>\n      </SuppressStartupBanner>\n      <UseFullPaths>false</UseFullPaths>\n      <WarningLevel>Level3</WarningLevel>\n      <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_WINDOWS;NDEBUG;ENABLE_OPENCL;ENABLE_VIDEO;ENABLE_PREVIEW_GUI;ENABLE_IMAGE_IO;ANIME4KCPP_CORE_PARALLEL_LIBRARY=\"PPL\";ANIME4KCPP_CORE_COMPILER=\"MSVC\";ANIME4KCPP_CORE_BUILD_DATE=\"2021-10-01\";ANIME4KCPP_CORE_VERSION=\"2.6.0\";ANIME4KCPP_CORE_VERSION_MAJOR=2;ANIME4KCPP_CORE_VERSION_MINOR=6;ANIME4KCPP_CORE_VERSION_PATCH=0;ANIME4KCPP_CORE_VERSION_STATUS=\"dev\";BUILT_IN_KERNEL;USE_PPL;CMAKE_INTDIR=\"Release\"</PreprocessorDefinitions>\n      <ObjectFileName>$(IntDir)</ObjectFileName>\n    </ClCompile>\n    <ResourceCompile>\n      <PreprocessorDefinitions>%(PreprocessorDefinitions);WIN32;_WINDOWS;NDEBUG;ENABLE_OPENCL;ENABLE_VIDEO;ENABLE_PREVIEW_GUI;ENABLE_IMAGE_IO;ANIME4KCPP_CORE_PARALLEL_LIBRARY=\\\"PPL\\\";ANIME4KCPP_CORE_COMPILER=\\\"MSVC\\\";ANIME4KCPP_CORE_BUILD_DATE=\\\"2021-10-01\\\";ANIME4KCPP_CORE_VERSION=\\\"2.6.0\\\";ANIME4KCPP_CORE_VERSION_MAJOR=2;ANIME4KCPP_CORE_VERSION_MINOR=6;ANIME4KCPP_CORE_VERSION_PATCH=0;ANIME4KCPP_CORE_VERSION_STATUS=\\\"dev\\\";BUILT_IN_KERNEL;USE_PPL;CMAKE_INTDIR=\\\"Release\\\"</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>Anime4KCPP\\core\\include;Anime4KCPP\\build\\core;Anime4KCPP\\ThirdParty\\include\\opencl;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;$(INTELOCLSDKROOT)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <Midl>\n      <AdditionalIncludeDirectories>Anime4KCPP\\core\\include;Anime4KCPP\\build\\core;Anime4KCPP\\ThirdParty\\include\\opencl;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;$(INTELOCLSDKROOT)\\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <OutputDirectory>$(ProjectDir)/$(IntDir)</OutputDirectory>\n      <HeaderFileName>%(Filename).h</HeaderFileName>\n      <TypeLibraryName>%(Filename).tlb</TypeLibraryName>\n      <InterfaceIdentifierFileName>%(Filename)_i.c</InterfaceIdentifierFileName>\n      <ProxyFileName>%(Filename)_p.c</ProxyFileName>\n    </Midl>\n    <Lib>\n      <AdditionalOptions>\n      </AdditionalOptions>\n    </Lib>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\AC.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACCPU.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACCreator.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACCuda.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACException.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACInitializer.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACManager.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACNCNN.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACNetType.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACOpenCL.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACProcessor.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACRegister.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\Anime4KCPP.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CNN.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CPUACNet.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CPUACNetProcessor.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CPUAnime4K09.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CPUCNNProcessor.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CoreInfo.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CudaACNet.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CudaAnime4K09.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CudaInterface.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\FilterProcessor.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\NCNNACNet.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\NCNNACNetID.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\NCNNACNetModel.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\OpenCLACNet.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\OpenCLACNetKernel.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\OpenCLAnime4K09.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\OpenCLAnime4K09Kernel.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\Parallel.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ThreadPool.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\VideoCodec.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\VideoIO.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\VideoIOAsync.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\VideoIOSerial.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\VideoIOThreads.hpp\" />\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\VideoProcessor.hpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\AC.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\ACCreator.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\ACCuda.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\ACNCNN.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\ACOpenCL.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CPUACNet.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CPUACNetProcessor.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CPUAnime4K09.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CPUCNNProcessor.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CoreInfo.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CudaACNet.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CudaAnime4K09.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\FilterProcessor.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\NCNNACNet.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\OpenCLACNet.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\OpenCLAnime4K09.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\VideoIO.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\VideoIOAsync.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\VideoIOSerial.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\VideoIOThreads.cpp\" />\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\VideoProcessor.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "Anime4KCPPCore.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\AC.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\ACCreator.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\ACCuda.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\ACNCNN.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\ACOpenCL.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CPUACNet.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CPUACNetProcessor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CPUAnime4K09.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CPUCNNProcessor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CoreInfo.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CudaACNet.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\CudaAnime4K09.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\FilterProcessor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\NCNNACNet.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\OpenCLACNet.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\OpenCLAnime4K09.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\VideoIO.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\VideoIOAsync.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\VideoIOSerial.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\VideoIOThreads.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Anime4KCPP\\core\\src\\VideoProcessor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\AC.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACCPU.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACCreator.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACCuda.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACException.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACInitializer.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACManager.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACNCNN.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACNetType.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACOpenCL.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACProcessor.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ACRegister.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\Anime4KCPP.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CNN.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CPUACNet.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CPUACNetProcessor.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CPUAnime4K09.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CPUCNNProcessor.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CoreInfo.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CudaACNet.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CudaAnime4K09.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\CudaInterface.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\FilterProcessor.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\NCNNACNet.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\NCNNACNetID.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\NCNNACNetModel.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\OpenCLACNet.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\OpenCLACNetKernel.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\OpenCLAnime4K09.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\OpenCLAnime4K09Kernel.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\Parallel.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\ThreadPool.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\VideoCodec.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\VideoIO.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\VideoIOAsync.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\VideoIOSerial.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\VideoIOThreads.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Anime4KCPP\\core\\include\\VideoProcessor.hpp\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{047624CC-513D-36E8-B51C-5F37C672EBF6}</UniqueIdentifier>\n    </Filter>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{788BFBE6-65CD-3D66-A4BD-D9B8297F3AEF}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Dlls/Dlls.csproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"14.0\" DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <PropertyGroup>\n    <Configuration>Release</Configuration>\n    <ProjectGuid>{BC1BC9F1-893D-4715-818A-F37F74EB5710}</ProjectGuid>\n    <OutputType>Library</OutputType>\n    <AppDesignerFolder>Properties</AppDesignerFolder>\n    <RootNamespace>Dlls</RootNamespace>\n    <AssemblyName>Dlls</AssemblyName>\n    <FileAlignment>512</FileAlignment>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)' == 'Debug' \">\n    <DebugSymbols>true</DebugSymbols>\n    <DebugType>full</DebugType>\n    <Optimize>false</Optimize>\n    <OutputPath>bin\\Debug\\</OutputPath>\n    <DefineConstants>DEBUG;TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <PropertyGroup Condition=\" '$(Configuration)' == 'Release' \">\n    <DebugType>pdbonly</DebugType>\n    <Optimize>true</Optimize>\n    <OutputPath>bin\\Release\\</OutputPath>\n    <DefineConstants>TRACE</DefineConstants>\n    <ErrorReport>prompt</ErrorReport>\n    <WarningLevel>4</WarningLevel>\n  </PropertyGroup>\n  <ItemGroup>\n    <Content Include=\"..\\Release\\*.dll\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </Content>\n  </ItemGroup>\n  <Import Project=\"$(MSBuildToolsPath)\\Microsoft.CSharp.targets\" />\n  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. \n       Other similar extension points exist, see Microsoft.Common.targets.\n  <Target Name=\"BeforeBuild\">\n  </Target>\n  <Target Name=\"AfterBuild\">\n  </Target>\n  -->\n</Project>"
  },
  {
    "path": "HttpDownload/HttpDownload.cpp",
    "content": "// HttpDownload.cpp : Defines the entry point for the console application.\n//\n\n#include \"stdafx.h\"\n\n#include \"http_download.h\"\n\n#include <stdlib.h>\n#include <exception>\n#include <iostream>\n\nint _tmain(int argc, TCHAR *argv[])\n{\n    if (argc != 3)\n        return EXIT_FAILURE;\n    try\n    {\n        const bool ok = HttpDownload(argv[1], argv[2]);\n        return ok ? EXIT_SUCCESS : EXIT_FAILURE;\n    }\n    catch (const std::exception& ex)\n    { \n        std::cerr << ex.what() << '\\n';\n        return EXIT_FAILURE;\n    }\n}\n"
  },
  {
    "path": "HttpDownload/HttpDownload.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{A4113679-4736-494B-B8D2-3C35B34E5491}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>HttpDownload</RootNamespace>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>../networking;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>Winhttp.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>../networking;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>Winhttp.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>../networking;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>Winhttp.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>../networking;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>Winhttp.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <Text Include=\"ReadMe.txt\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"stdafx.h\" />\n    <ClInclude Include=\"targetver.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"HttpDownload.cpp\" />\n    <ClCompile Include=\"stdafx.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\networking\\networking.vcxproj\">\n      <Project>{3de6c2d2-fdfc-4745-8282-981df7561405}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "HttpDownload/HttpDownload.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <Text Include=\"ReadMe.txt\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"stdafx.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"targetver.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"stdafx.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"HttpDownload.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "HttpDownload/ReadMe.txt",
    "content": "========================================================================\n    CONSOLE APPLICATION : HttpDownload Project Overview\n========================================================================\n\nAppWizard has created this HttpDownload application for you.\n\nThis file contains a summary of what you will find in each of the files that\nmake up your HttpDownload application.\n\n\nHttpDownload.vcxproj\n    This is the main project file for VC++ projects generated using an Application Wizard.\n    It contains information about the version of Visual C++ that generated the file, and\n    information about the platforms, configurations, and project features selected with the\n    Application Wizard.\n\nHttpDownload.vcxproj.filters\n    This is the filters file for VC++ projects generated using an Application Wizard. \n    It contains information about the association between the files in your project \n    and the filters. This association is used in the IDE to show grouping of files with\n    similar extensions under a specific node (for e.g. \".cpp\" files are associated with the\n    \"Source Files\" filter).\n\nHttpDownload.cpp\n    This is the main application source file.\n\n/////////////////////////////////////////////////////////////////////////////\nOther standard files:\n\nStdAfx.h, StdAfx.cpp\n    These files are used to build a precompiled header (PCH) file\n    named HttpDownload.pch and a precompiled types file named StdAfx.obj.\n\n/////////////////////////////////////////////////////////////////////////////\nOther notes:\n\nAppWizard uses \"TODO:\" comments to indicate parts of the source code you\nshould add to or customize.\n\n/////////////////////////////////////////////////////////////////////////////\n"
  },
  {
    "path": "HttpDownload/stdafx.cpp",
    "content": "// stdafx.cpp : source file that includes just the standard includes\n// HttpDownload.pch will be the pre-compiled header\n// stdafx.obj will contain the pre-compiled type information\n\n#include \"stdafx.h\"\n\n// TODO: reference any additional headers you need in STDAFX.H\n// and not in this file\n"
  },
  {
    "path": "HttpDownload/stdafx.h",
    "content": "// stdafx.h : include file for standard system include files,\n// or project specific include files that are used frequently, but\n// are changed infrequently\n//\n\n#pragma once\n\n#include \"targetver.h\"\n\n#include <stdio.h>\n#include <tchar.h>\n\n\n\n// TODO: reference additional headers your program requires here\n"
  },
  {
    "path": "HttpDownload/targetver.h",
    "content": "#pragma once\n\n// Including SDKDDKVer.h defines the highest available Windows platform.\n\n// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and\n// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.\n\n#include <SDKDDKVer.h>\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Player/AsyncGetUrlUnderMouseCursor.cpp",
    "content": "#include \"stdafx.h\"\n\n#include \"AsyncGetUrlUnderMouseCursor.h\"\n\nnamespace {\n\nclass CComUsageScope\n{\n    bool m_bInitialized;\npublic:\n    explicit CComUsageScope(DWORD dwCoInit = COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY)\n    {\n        m_bInitialized = SUCCEEDED(CoInitializeEx(NULL, dwCoInit));\n    }\n    ~CComUsageScope()\n    {\n        if (m_bInitialized)\n            CoUninitialize();\n    }\n};\n\nbool LinkHandled(const CComPtr<IAccessible>& pacc)\n{\n    VARIANT v;\n    v.vt = VT_I4;\n    v.lVal = CHILDID_SELF;\n\n    CComVariant vRole;\n    if (SUCCEEDED(pacc->get_accRole(v, &vRole)) && vRole.vt == VT_I4 && vRole.lVal == ROLE_SYSTEM_LINK)\n    {\n        CComBSTR url;\n        if (SUCCEEDED(pacc->get_accValue(v, &url)) && url != NULL)\n        {\n            AfxGetApp()->PostThreadMessage(WM_ON_ASYNC_URL, (WPARAM)url.Detach(), NULL);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nVOID CALLBACK SendAsyncProc(\n    HWND,\n    UINT,\n    ULONG_PTR dwData,\n    LRESULT lResult)\n{\n    CComUsageScope scope;\n\n    CComPtr<IAccessible> pacc_;\n    if (FAILED(ObjectFromLresult(lResult, __uuidof(IAccessible), 0, (void**)&pacc_)))\n        return;\n\n    enum { MAX_ITER_NUM = 100 };\n\n    POINT ptScreen{ LOWORD(dwData), HIWORD(dwData) };\n\n    for (int i = 0; i < 2; ++i)\n    {\n        CComPtr<IAccessible> pacc = pacc_;\n        {\n            int iter = 0;\n            CComVariant vtChild;\n            CComQIPtr<IAccessible> paccChild;\n            for (; SUCCEEDED(pacc->accHitTest(ptScreen.x, ptScreen.y, &vtChild))\n                && VT_DISPATCH == vtChild.vt && (paccChild = vtChild.pdispVal) != NULL;\n                vtChild.Clear())\n            {\n                if (LinkHandled(pacc))\n                    return;\n\n                if (iter++ >= MAX_ITER_NUM)\n                    return;\n                pacc.Attach(paccChild.Detach());\n            }\n        }\n\n        int iter = 0;\n        while (pacc)\n        {\n            if (LinkHandled(pacc))\n                return;\n\n            if (iter++ >= MAX_ITER_NUM)\n                return;\n\n            CComPtr<IDispatch> spDisp;\n            if (FAILED(pacc->get_accParent(&spDisp)))\n                return;\n            CComQIPtr<IAccessible> spParent(spDisp);\n            pacc.Attach(spParent.Detach());\n        }\n\n        if (i == 0)\n        {\n            ::Sleep(100);\n        }\n    }\n}\n\n} // namespace\n\n\nvoid AsyncGetUrlUnderMouseCursor()\n{\n    POINT pt;\n    if (!GetCursorPos(&pt))\n        return;\n\n    HWND hWnd = WindowFromPoint(pt);\n    if (NULL == hWnd)\n        return;\n\n    TCHAR szBuffer[64];\n\n    const int classNameLength\n        = ::GetClassName(hWnd, szBuffer, sizeof(szBuffer) / sizeof(szBuffer[0]));\n\n    szBuffer[sizeof(szBuffer) / sizeof(szBuffer[0]) - 1] = _T('\\0');\n\n    if (_tcscmp(szBuffer, _T(\"MozillaWindowClass\")) != 0 && _tcscmp(szBuffer, _T(\"Chrome_RenderWidgetHostHWND\")) != 0)\n        return;\n\n    VERIFY(SendMessageCallback(hWnd, WM_GETOBJECT, 0L, OBJID_CLIENT, SendAsyncProc, MAKELONG(pt.x, pt.y)));\n}\n"
  },
  {
    "path": "Player/AsyncGetUrlUnderMouseCursor.h",
    "content": "#pragma once\n\nenum { WM_ON_ASYNC_URL = 1234 };\n\nvoid AsyncGetUrlUnderMouseCursor();\n"
  },
  {
    "path": "Player/ByteStreamBuffer.h",
    "content": "#pragma once\n\n#include <streambuf>\n\nclass ByteStreamBuffer: public std::streambuf\n{\npublic:\n    ByteStreamBuffer(char* base, size_t length)\n    {\n        setg(base, base, base + length);\n    }\n\nprotected:\n    pos_type seekoff( off_type offset,\n                              std::ios_base::seekdir dir,\n                              std::ios_base::openmode ) override\n    {\n        char* whence = eback();\n        if (dir == std::ios_base::cur)\n        {\n            whence = gptr();\n        }\n        else if (dir == std::ios_base::end)\n        {\n            whence = egptr();\n        }\n        char* to = whence + offset;\n\n        // check limits\n        if (to >= eback() && to <= egptr())\n        {\n            setg(eback(), to, egptr());\n            return gptr() - eback();\n        }\n\n        return -1;\n    }\n};\n"
  },
  {
    "path": "Player/D3DFONT.CPP",
    "content": "//-----------------------------------------------------------------------------\n// File: D3DFont.cpp\n//\n// Desc: Texture-based font class\n//-----------------------------------------------------------------------------\n#include \"stdafx.h\"\n#ifndef STRICT\n#define STRICT\n#endif\n#include <stdio.h>\n#include <tchar.h>\n//#include <D3DX9.h>\n#include \"D3DFont.h\"\n//#include \"D3DUtil.h\"\n//#include \"DXUtil.h\"\n\n\n#define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }\n\n\n//-----------------------------------------------------------------------------\n// Custom vertex types for rendering text\n//-----------------------------------------------------------------------------\n#define MAX_NUM_VERTICES 50*6\n\ntypedef struct D3DXVECTOR3 {\n    FLOAT x;\n    FLOAT y;\n    FLOAT z;\n} D3DXVECTOR3, *LPD3DXVECTOR3;\n\ntypedef struct D3DXVECTOR4 {\n    FLOAT x;\n    FLOAT y;\n    FLOAT z;\n    FLOAT w;\n} D3DXVECTOR4, *LPD3DXVECTOR4;\n\nstruct FONT2DVERTEX { D3DXVECTOR4 p;   DWORD color;     FLOAT tu, tv; };\nstruct FONT3DVERTEX { D3DXVECTOR3 p;   D3DXVECTOR3 n;   FLOAT tu, tv; };\n\n#define D3DFVF_FONT2DVERTEX (D3DFVF_XYZRHW|D3DFVF_DIFFUSE|D3DFVF_TEX1)\n#define D3DFVF_FONT3DVERTEX (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)\n\ninline FONT2DVERTEX InitFont2DVertex( const D3DXVECTOR4& p, D3DCOLOR color,\n                                      FLOAT tu, FLOAT tv )\n{\n    FONT2DVERTEX v;   v.p = p;   v.color = color;   v.tu = tu;   v.tv = tv;\n    return v;\n}\n\ninline FONT3DVERTEX InitFont3DVertex( const D3DXVECTOR3& p, const D3DXVECTOR3& n,\n                                      FLOAT tu, FLOAT tv )\n{\n    FONT3DVERTEX v;   v.p = p;   v.n = n;   v.tu = tu;   v.tv = tv;\n    return v;\n}\n\n\n\n\n//-----------------------------------------------------------------------------\n// Name: CD3DFont()\n// Desc: Font class constructor\n//-----------------------------------------------------------------------------\nCD3DFont::CD3DFont( const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags )\n{\n    _tcsncpy_s( m_strFontName, strFontName, sizeof(m_strFontName) / sizeof(TCHAR) );\n    m_strFontName[sizeof(m_strFontName) / sizeof(TCHAR) - 1] = _T('\\0');\n    m_dwFontHeight         = dwHeight;\n    m_dwFontFlags          = dwFlags;\n    m_dwSpacing            = 0;\n\n    m_pd3dDevice           = NULL;\n    m_pTexture             = NULL;\n    m_pVB                  = NULL;\n\n    m_pStateBlockSaved     = NULL;\n    m_pStateBlockDrawText  = NULL;\n}\n\n\n\n\n//-----------------------------------------------------------------------------\n// Name: ~CD3DFont()\n// Desc: Font class destructor\n//-----------------------------------------------------------------------------\nCD3DFont::~CD3DFont()\n{\n    InvalidateDeviceObjects();\n    DeleteDeviceObjects();\n}\n\n\n\n\n//-----------------------------------------------------------------------------\n// Name: InitDeviceObjects()\n// Desc: Initializes device-dependent objects, including the vertex buffer used\n//       for rendering text and the texture map which stores the font image.\n//-----------------------------------------------------------------------------\nHRESULT CD3DFont::InitDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice )\n{\n    HRESULT hr;\n\n    // Keep a local copy of the device\n    m_pd3dDevice = pd3dDevice;\n\n    // Establish the font and texture size\n    m_fTextScale  = 1.0f; // Draw fonts into texture without scaling\n\n    // Large fonts need larger textures\n    if( m_dwFontHeight > 60 )\n        m_dwTexWidth = m_dwTexHeight = 2048;\n    else if( m_dwFontHeight > 30 )\n        m_dwTexWidth = m_dwTexHeight = 1024;\n    else if( m_dwFontHeight > 15 )\n        m_dwTexWidth = m_dwTexHeight = 512;\n    else\n        m_dwTexWidth  = m_dwTexHeight = 256;\n\n    // If requested texture is too big, use a smaller texture and smaller font,\n    // and scale up when rendering.\n    D3DCAPS9 d3dCaps;\n    m_pd3dDevice->GetDeviceCaps( &d3dCaps );\n\n    if( m_dwTexWidth > d3dCaps.MaxTextureWidth )\n    {\n        m_fTextScale = (FLOAT)d3dCaps.MaxTextureWidth / (FLOAT)m_dwTexWidth;\n        m_dwTexWidth = m_dwTexHeight = d3dCaps.MaxTextureWidth;\n    }\n\n    // Create a new texture for the font\n    hr = m_pd3dDevice->CreateTexture( m_dwTexWidth, m_dwTexHeight, 1,\n                                      0, D3DFMT_A4R4G4B4,\n                                      D3DPOOL_MANAGED, &m_pTexture, NULL );\n    if( FAILED(hr) )\n        return hr;\n\n    // Prepare to create a bitmap\n    DWORD*      pBitmapBits;\n    BITMAPINFO bmi;\n    ZeroMemory( &bmi.bmiHeader,  sizeof(BITMAPINFOHEADER) );\n    bmi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);\n    bmi.bmiHeader.biWidth       =  (int)m_dwTexWidth;\n    bmi.bmiHeader.biHeight      = -(int)m_dwTexHeight;\n    bmi.bmiHeader.biPlanes      = 1;\n    bmi.bmiHeader.biCompression = BI_RGB;\n    bmi.bmiHeader.biBitCount    = 32;\n\n    // Create a DC and a bitmap for the font\n    HDC     hDC       = CreateCompatibleDC( NULL );\n    HBITMAP hbmBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,\n                                          (void**)&pBitmapBits, NULL, 0 );\n    SetMapMode( hDC, MM_TEXT );\n\n    // Create a font.  By specifying ANTIALIASED_QUALITY, we might get an\n    // antialiased font, but this is not guaranteed.\n    INT nHeight    = -MulDiv( m_dwFontHeight, \n        (INT)(GetDeviceCaps(hDC, LOGPIXELSY) * m_fTextScale), 72 );\n    DWORD dwBold   = (m_dwFontFlags&D3DFONT_BOLD)   ? FW_BOLD : FW_NORMAL;\n    DWORD dwItalic = (m_dwFontFlags&D3DFONT_ITALIC) ? TRUE    : FALSE;\n    HFONT hFont    = CreateFont( nHeight, 0, 0, 0, dwBold, dwItalic,\n                          FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,\n                          CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,\n                          VARIABLE_PITCH, m_strFontName );\n    if (NULL == hFont)\n    {\n        DeleteObject(hbmBitmap);\n        DeleteDC(hDC);\n        return E_FAIL;\n    }\n\n    HGDIOBJ hbmOld = SelectObject( hDC, hbmBitmap );\n    HGDIOBJ hFontOld = SelectObject( hDC, hFont );\n\n    // Set text properties\n    SetTextColor( hDC, RGB(255,255,255) );\n    SetBkColor(   hDC, 0x00000000 );\n    SetTextAlign( hDC, TA_TOP );\n\n    // Loop through all printable character and output them to the bitmap..\n    // Meanwhile, keep track of the corresponding tex coords for each character.\n    DWORD x = 0;\n    DWORD y = 0;\n    TCHAR str[2] = _T(\"x\");\n    SIZE size;\n\n    // Calculate the spacing between characters based on line height\n    GetTextExtentPoint32( hDC, TEXT(\" \"), 1, &size );\n    x = m_dwSpacing = (DWORD) ceil(size.cy * 0.3f);\n\n    for( TCHAR c=32; c<127; c++ )\n    {\n        str[0] = c;\n        GetTextExtentPoint32( hDC, str, 1, &size );\n\n        if( (DWORD)(x + size.cx + m_dwSpacing) > m_dwTexWidth )\n        {\n            x  = m_dwSpacing;\n            y += size.cy+1;\n        }\n\n        ExtTextOut( hDC, x+0, y+0, ETO_OPAQUE, NULL, str, 1, NULL );\n\n        m_fTexCoords[c-32][0] = ((FLOAT)(x + 0       - m_dwSpacing))/m_dwTexWidth;\n        m_fTexCoords[c-32][1] = ((FLOAT)(y + 0       + 0          ))/m_dwTexHeight;\n        m_fTexCoords[c-32][2] = ((FLOAT)(x + size.cx + m_dwSpacing))/m_dwTexWidth;\n        m_fTexCoords[c-32][3] = ((FLOAT)(y + size.cy + 0          ))/m_dwTexHeight;\n\n        x += size.cx + (2 * m_dwSpacing);\n    }\n\n    // Lock the surface and write the alpha values for the set pixels\n    D3DLOCKED_RECT d3dlr;\n    m_pTexture->LockRect( 0, &d3dlr, 0, 0 );\n    BYTE* pDstRow = (BYTE*)d3dlr.pBits;\n\n    for( y=0; y < m_dwTexHeight; y++ )\n    {\n        WORD* pDst16 = (WORD*)pDstRow;\n        for( x=0; x < m_dwTexWidth; x++ )\n        {\n            BYTE bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4); // 4-bit measure of pixel intensity\n            if (bAlpha > 0)\n            {\n                *pDst16++ = (WORD) ((bAlpha << 12) | 0x0fff);\n            }\n            else\n            {\n                *pDst16++ = 0x0000;\n            }\n        }\n        pDstRow += d3dlr.Pitch;\n    }\n\n    // Done updating texture, so clean up used objects\n    m_pTexture->UnlockRect(0);\n    SelectObject( hDC, hbmOld );\n    SelectObject( hDC, hFontOld );\n    DeleteObject( hbmBitmap );\n    DeleteObject( hFont );\n    DeleteDC( hDC );\n\n    return S_OK;\n}\n\n\n\n\n//-----------------------------------------------------------------------------\n// Name: RestoreDeviceObjects()\n// Desc:\n//-----------------------------------------------------------------------------\nHRESULT CD3DFont::RestoreDeviceObjects()\n{\n    HRESULT hr;\n\n    // Create vertex buffer for the letters\n    int vertexSize = max( sizeof(FONT2DVERTEX), sizeof(FONT3DVERTEX ) );\n    if( FAILED( hr = m_pd3dDevice->CreateVertexBuffer( MAX_NUM_VERTICES * vertexSize,\n                                                       D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,\n                                                       D3DPOOL_DEFAULT, &m_pVB, NULL ) ) )\n    {\n        return hr;\n    }\n\n    // Create the state blocks for rendering text\n    for( UINT which=0; which<2; which++ )\n    {\n        m_pd3dDevice->BeginStateBlock();\n        m_pd3dDevice->SetTexture( 0, m_pTexture );\n\n        if ( D3DFONT_ZENABLE & m_dwFontFlags )\n            m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );\n        else\n            m_pd3dDevice->SetRenderState( D3DRS_ZENABLE, FALSE );\n\n        m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );\n        m_pd3dDevice->SetRenderState( D3DRS_SRCBLEND,   D3DBLEND_SRCALPHA );\n        m_pd3dDevice->SetRenderState( D3DRS_DESTBLEND,  D3DBLEND_INVSRCALPHA );\n        m_pd3dDevice->SetRenderState( D3DRS_ALPHATESTENABLE,  TRUE );\n        m_pd3dDevice->SetRenderState( D3DRS_ALPHAREF,         0x08 );\n        m_pd3dDevice->SetRenderState( D3DRS_ALPHAFUNC,  D3DCMP_GREATEREQUAL );\n        m_pd3dDevice->SetRenderState( D3DRS_FILLMODE,   D3DFILL_SOLID );\n        m_pd3dDevice->SetRenderState( D3DRS_CULLMODE,   D3DCULL_CCW );\n        m_pd3dDevice->SetRenderState( D3DRS_STENCILENABLE,    FALSE );\n        m_pd3dDevice->SetRenderState( D3DRS_CLIPPING,         TRUE );\n        m_pd3dDevice->SetRenderState( D3DRS_CLIPPLANEENABLE,  FALSE );\n        m_pd3dDevice->SetRenderState( D3DRS_VERTEXBLEND,      D3DVBF_DISABLE );\n        m_pd3dDevice->SetRenderState( D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE );\n        m_pd3dDevice->SetRenderState( D3DRS_FOGENABLE,        FALSE );\n        m_pd3dDevice->SetRenderState( D3DRS_COLORWRITEENABLE,\n            D3DCOLORWRITEENABLE_RED  | D3DCOLORWRITEENABLE_GREEN |\n            D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA );\n        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );\n        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );\n        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );\n        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_MODULATE );\n        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );\n        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );\n        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXCOORDINDEX, 0 );\n        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE );\n        m_pd3dDevice->SetTextureStageState( 1, D3DTSS_COLOROP,   D3DTOP_DISABLE );\n        m_pd3dDevice->SetTextureStageState( 1, D3DTSS_ALPHAOP,   D3DTOP_DISABLE );\n        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_POINT );\n        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_POINT );\n        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MIPFILTER, D3DTEXF_NONE );\n\n        if( which==0 )\n            m_pd3dDevice->EndStateBlock( &m_pStateBlockSaved );\n        else\n            m_pd3dDevice->EndStateBlock( &m_pStateBlockDrawText );\n    }\n\n    return S_OK;\n}\n\n\n\n\n//-----------------------------------------------------------------------------\n// Name: InvalidateDeviceObjects()\n// Desc: Destroys all device-dependent objects\n//-----------------------------------------------------------------------------\nHRESULT CD3DFont::InvalidateDeviceObjects()\n{\n    SAFE_RELEASE( m_pVB );\n    SAFE_RELEASE( m_pStateBlockSaved );\n    SAFE_RELEASE( m_pStateBlockDrawText );\n\n    return S_OK;\n}\n\n\n\n\n//-----------------------------------------------------------------------------\n// Name: DeleteDeviceObjects()\n// Desc: Destroys all device-dependent objects\n//-----------------------------------------------------------------------------\nHRESULT CD3DFont::DeleteDeviceObjects()\n{\n    SAFE_RELEASE( m_pTexture );\n    m_pd3dDevice = NULL;\n\n    return S_OK;\n}\n\n\n\n\n//-----------------------------------------------------------------------------\n// Name: GetTextExtent()\n// Desc: Get the dimensions of a text string\n//-----------------------------------------------------------------------------\nHRESULT CD3DFont::GetTextExtent( const TCHAR* strText, SIZE* pSize )\n{\n    if( NULL==strText || NULL==pSize )\n        return E_FAIL;\n\n    FLOAT fRowWidth  = 0.0f;\n    FLOAT fRowHeight = (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;\n    FLOAT fWidth     = 0.0f;\n    FLOAT fHeight    = fRowHeight;\n\n    while( *strText )\n    {\n        TCHAR c = *strText++;\n\n        if( c == _T('\\n') )\n        {\n            if (*strText == _T('\\0'))\n                break;\n            fRowWidth = 0.0f;\n            fHeight  += fRowHeight;\n        }\n\n        if( (c-32) < 0 || (c-32) >= 128-32 )\n            continue;\n\n        FLOAT tx1 = m_fTexCoords[c-32][0];\n        FLOAT tx2 = m_fTexCoords[c-32][2];\n\n        fRowWidth += (tx2-tx1)*m_dwTexWidth - 2*m_dwSpacing;\n\n        if( fRowWidth > fWidth )\n            fWidth = fRowWidth;\n    }\n\n    pSize->cx = (int)fWidth;\n    pSize->cy = (int)fHeight;\n\n    return S_OK;\n}\n\n\n\n\n//-----------------------------------------------------------------------------\n// Name: DrawTextScaled()\n// Desc: Draws scaled 2D text.  Note that x and y are in viewport coordinates\n//       (ranging from -1 to +1).  fXScale and fYScale are the size fraction \n//       relative to the entire viewport.  For example, a fXScale of 0.25 is\n//       1/8th of the screen width.  This allows you to output text at a fixed\n//       fraction of the viewport, even if the screen or window size changes.\n//-----------------------------------------------------------------------------\nHRESULT CD3DFont::DrawTextScaled( FLOAT x, FLOAT y, FLOAT z,\n                                  FLOAT fXScale, FLOAT fYScale, DWORD dwColor,\n                                  const TCHAR* strText, DWORD dwFlags )\n{\n    if( m_pd3dDevice == NULL )\n        return E_FAIL;\n\n    // Set up renderstate\n    m_pStateBlockSaved->Capture();\n    m_pStateBlockDrawText->Apply();\n    m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );\n    m_pd3dDevice->SetPixelShader( NULL );\n    m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );\n\n    // Set filter states\n    if( dwFlags & D3DFONT_FILTERED )\n    {\n        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );\n        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );\n    }\n\n    D3DVIEWPORT9 vp;\n    m_pd3dDevice->GetViewport( &vp );\n    FLOAT fLineHeight = ( m_fTexCoords[0][3] - m_fTexCoords[0][1] ) * m_dwTexHeight;\n\n    // Center the text block in the viewport\n    if( dwFlags & D3DFONT_CENTERED_X )\n    {\n        const TCHAR* strTextTmp = strText;\n        float xFinal = 0.0f;\n\n        while( *strTextTmp )\n        {\n            TCHAR c = *strTextTmp++;\n    \n            if( c == _T('\\n') )\n                break;  // Isn't supported.  \n            if( (c-32) < 0 || (c-32) >= 128-32 )\n                continue;\n\n            FLOAT tx1 = m_fTexCoords[c-32][0];\n            FLOAT tx2 = m_fTexCoords[c-32][2];\n\n            FLOAT w = (tx2-tx1)*m_dwTexWidth;\n\n            w *= (fXScale*vp.Height)/fLineHeight;\n\n            xFinal += w - (2 * m_dwSpacing) * (fXScale*vp.Height)/fLineHeight;\n        }\n\n        x = -xFinal/vp.Width;\n    }\n    if( dwFlags & D3DFONT_CENTERED_Y )\n    {\n        y = -fLineHeight/vp.Height;\n    }\n\n    FLOAT sx  = (x+1.0f)*vp.Width/2;\n    FLOAT sy  = (y+1.0f)*vp.Height/2;\n    FLOAT sz  = z;\n    FLOAT rhw = 1.0f;\n\n    // Adjust for character spacing\n    sx -= m_dwSpacing * (fXScale*vp.Height)/fLineHeight;\n    FLOAT fStartX = sx;\n\n    // Fill vertex buffer\n    FONT2DVERTEX* pVertices;\n    DWORD         dwNumTriangles = 0L;\n    m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );\n\n    while( *strText )\n    {\n        TCHAR c = *strText++;\n\n        if( c == _T('\\n') )\n        {\n            sx  = fStartX;\n            sy += fYScale*vp.Height;\n        }\n\n        if( (c-32) < 0 || (c-32) >= 128-32 )\n            continue;\n\n        FLOAT tx1 = m_fTexCoords[c-32][0];\n        FLOAT ty1 = m_fTexCoords[c-32][1];\n        FLOAT tx2 = m_fTexCoords[c-32][2];\n        FLOAT ty2 = m_fTexCoords[c-32][3];\n\n        FLOAT w = (tx2-tx1)*m_dwTexWidth;\n        FLOAT h = (ty2-ty1)*m_dwTexHeight;\n\n        w *= (fXScale*vp.Height)/fLineHeight;\n        h *= (fYScale*vp.Height)/fLineHeight;\n\n        if( c != _T(' ') )\n        {\n            *pVertices++ = InitFont2DVertex({ sx + 0 - 0.5f, sy + h - 0.5f, sz, rhw }, dwColor, tx1, ty2);\n            *pVertices++ = InitFont2DVertex({ sx + 0 - 0.5f, sy + 0 - 0.5f, sz, rhw }, dwColor, tx1, ty1);\n            *pVertices++ = InitFont2DVertex({ sx + w - 0.5f, sy + h - 0.5f, sz, rhw }, dwColor, tx2, ty2);\n            *pVertices++ = InitFont2DVertex({ sx + w - 0.5f, sy + 0 - 0.5f, sz, rhw }, dwColor, tx2, ty1);\n            *pVertices++ = InitFont2DVertex({ sx + w - 0.5f, sy + h - 0.5f, sz, rhw }, dwColor, tx2, ty2);\n            *pVertices++ = InitFont2DVertex({ sx + 0 - 0.5f, sy + 0 - 0.5f, sz, rhw }, dwColor, tx1, ty1);\n            dwNumTriangles += 2;\n\n            if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )\n            {\n                // Unlock, render, and relock the vertex buffer\n                m_pVB->Unlock();\n                m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );\n                m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );\n                dwNumTriangles = 0L;\n            }\n        }\n\n        sx += w - (2 * m_dwSpacing) * (fXScale*vp.Height)/fLineHeight;\n    }\n\n    // Unlock and render the vertex buffer\n    m_pVB->Unlock();\n    if( dwNumTriangles > 0 )\n        m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );\n\n    // Restore the modified renderstates\n    m_pStateBlockSaved->Apply();\n\n    return S_OK;\n}\n\n\n\n\n//-----------------------------------------------------------------------------\n// Name: DrawText()\n// Desc: Draws 2D text. Note that sx and sy are in pixels\n//-----------------------------------------------------------------------------\nHRESULT CD3DFont::DrawText( FLOAT sx, FLOAT sy, DWORD dwColor,\n                            const TCHAR* strText, DWORD dwFlags )\n{\n    if( m_pd3dDevice == NULL )\n        return E_FAIL;\n\n    // Setup renderstate\n    m_pStateBlockSaved->Capture();\n    m_pStateBlockDrawText->Apply();\n    m_pd3dDevice->SetFVF( D3DFVF_FONT2DVERTEX );\n    m_pd3dDevice->SetPixelShader( NULL );\n    m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT2DVERTEX) );\n\n    // Set filter states\n    if( dwFlags & D3DFONT_FILTERED )\n    {\n        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );\n        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );\n    }\n\n    // Center the text block in the viewport\n    if( dwFlags & D3DFONT_CENTERED_X )\n    {\n        D3DVIEWPORT9 vp;\n        m_pd3dDevice->GetViewport( &vp );\n        const TCHAR* strTextTmp = strText;\n        float xFinal = 0.0f;\n\n        while( *strTextTmp )\n        {\n            TCHAR c = *strTextTmp++;\n    \n            if( c == _T('\\n') )\n                break;  // Isn't supported.  \n            if( (c-32) < 0 || (c-32) >= 128-32 )\n                continue;\n\n            FLOAT tx1 = m_fTexCoords[c-32][0];\n            FLOAT tx2 = m_fTexCoords[c-32][2];\n    \n            FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;\n    \n            xFinal += w - (2 * m_dwSpacing);\n        }\n\n        sx = (vp.Width-xFinal)/2.0f;\n    }\n    if( dwFlags & D3DFONT_CENTERED_Y )\n    {\n        D3DVIEWPORT9 vp;\n        m_pd3dDevice->GetViewport( &vp );\n        float fLineHeight = ((m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight);\n        sy = (vp.Height-fLineHeight)/2;\n    }\n\n    // Adjust for character spacing\n    sx -= m_dwSpacing;\n    FLOAT fStartX = sx;\n\n    // Fill vertex buffer\n    FONT2DVERTEX* pVertices = NULL;\n    DWORD         dwNumTriangles = 0;\n    m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );\n\n    while( *strText )\n    {\n        TCHAR c = *strText++;\n\n        if( c == _T('\\n') )\n        {\n            sx = fStartX;\n            sy += (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;\n        }\n\n        if( (c-32) < 0 || (c-32) >= 128-32 )\n            continue;\n\n        FLOAT tx1 = m_fTexCoords[c-32][0];\n        FLOAT ty1 = m_fTexCoords[c-32][1];\n        FLOAT tx2 = m_fTexCoords[c-32][2];\n        FLOAT ty2 = m_fTexCoords[c-32][3];\n\n        FLOAT w = (tx2-tx1) *  m_dwTexWidth / m_fTextScale;\n        FLOAT h = (ty2-ty1) * m_dwTexHeight / m_fTextScale;\n\n        if( c != _T(' ') )\n        {\n            *pVertices++ = InitFont2DVertex({ sx + 0 - 0.5f, sy + h - 0.5f, 0.9f, 1.0f }, dwColor, tx1, ty2);\n            *pVertices++ = InitFont2DVertex({ sx + 0 - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f }, dwColor, tx1, ty1);\n            *pVertices++ = InitFont2DVertex({ sx + w - 0.5f, sy + h - 0.5f, 0.9f, 1.0f }, dwColor, tx2, ty2);\n            *pVertices++ = InitFont2DVertex({ sx + w - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f }, dwColor, tx2, ty1);\n            *pVertices++ = InitFont2DVertex({ sx + w - 0.5f, sy + h - 0.5f, 0.9f, 1.0f }, dwColor, tx2, ty2);\n            *pVertices++ = InitFont2DVertex({ sx + 0 - 0.5f, sy + 0 - 0.5f, 0.9f, 1.0f }, dwColor, tx1, ty1);\n            dwNumTriangles += 2;\n\n            if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )\n            {\n                // Unlock, render, and relock the vertex buffer\n                m_pVB->Unlock();\n                m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );\n                pVertices = NULL;\n                m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );\n                dwNumTriangles = 0L;\n            }\n        }\n\n        sx += w - (2 * m_dwSpacing);\n    }\n\n    // Unlock and render the vertex buffer\n    m_pVB->Unlock();\n    if( dwNumTriangles > 0 )\n        m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );\n\n    // Restore the modified renderstates\n    m_pStateBlockSaved->Apply();\n\n    return S_OK;\n}\n\n\n\n\n//-----------------------------------------------------------------------------\n// Name: Render3DText()\n// Desc: Renders 3D text\n//-----------------------------------------------------------------------------\nHRESULT CD3DFont::Render3DText( const TCHAR* strText, DWORD dwFlags )\n{\n    if( m_pd3dDevice == NULL )\n        return E_FAIL;\n\n    // Setup renderstate\n    m_pStateBlockSaved->Capture();\n    m_pStateBlockDrawText->Apply();\n    m_pd3dDevice->SetFVF( D3DFVF_FONT3DVERTEX );\n    m_pd3dDevice->SetPixelShader( NULL );\n    m_pd3dDevice->SetStreamSource( 0, m_pVB, 0, sizeof(FONT3DVERTEX) );\n\n    // Set filter states\n    if( dwFlags & D3DFONT_FILTERED )\n    {\n        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR );\n        m_pd3dDevice->SetSamplerState( 0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR );\n    }\n\n    // Position for each text element\n    FLOAT x = 0.0f;\n    FLOAT y = 0.0f;\n\n    // Center the text block at the origin (not the viewport)\n    if( dwFlags & D3DFONT_CENTERED_X )\n    {\n        SIZE sz;\n        GetTextExtent( strText, &sz );\n        x = -(((FLOAT)sz.cx)/10.0f)/2.0f;\n    }\n    if( dwFlags & D3DFONT_CENTERED_Y )\n    {\n        SIZE sz;\n        GetTextExtent( strText, &sz );\n        y = -(((FLOAT)sz.cy)/10.0f)/2.0f;\n    }\n\n    // Turn off culling for two-sided text\n    if( dwFlags & D3DFONT_TWOSIDED )\n        m_pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );\n\n    // Adjust for character spacing\n    x -= m_dwSpacing / 10.0f;\n    FLOAT fStartX = x;\n    TCHAR c;\n\n    // Fill vertex buffer\n    FONT3DVERTEX* pVertices;\n    DWORD         dwNumTriangles = 0L;\n    m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );\n\n    while( (c = *strText++) != 0 )\n    {\n        if( c == '\\n' )\n        {\n            x = fStartX;\n            y -= (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight/10.0f;\n        }\n\n        if( (c-32) < 0 || (c-32) >= 128-32 )\n            continue;\n\n        FLOAT tx1 = m_fTexCoords[c-32][0];\n        FLOAT ty1 = m_fTexCoords[c-32][1];\n        FLOAT tx2 = m_fTexCoords[c-32][2];\n        FLOAT ty2 = m_fTexCoords[c-32][3];\n\n        FLOAT w = (tx2-tx1) * m_dwTexWidth  / ( 10.0f * m_fTextScale );\n        FLOAT h = (ty2-ty1) * m_dwTexHeight / ( 10.0f * m_fTextScale );\n\n        if( c != _T(' ') )\n        {\n            *pVertices++ = InitFont3DVertex({ x + 0, y + 0, 0 }, { 0, 0, -1 }, tx1, ty2);\n            *pVertices++ = InitFont3DVertex({ x + 0, y + h, 0 }, { 0, 0, -1 }, tx1, ty1);\n            *pVertices++ = InitFont3DVertex({ x + w, y + 0, 0 }, { 0, 0, -1 }, tx2, ty2);\n            *pVertices++ = InitFont3DVertex({ x + w, y + h, 0 }, { 0, 0, -1 }, tx2, ty1);\n            *pVertices++ = InitFont3DVertex({ x + w, y + 0, 0 }, { 0, 0, -1 }, tx2, ty2);\n            *pVertices++ = InitFont3DVertex({ x + 0, y + h, 0 }, { 0, 0, -1 }, tx1, ty1);\n            dwNumTriangles += 2;\n\n            if( dwNumTriangles*3 > (MAX_NUM_VERTICES-6) )\n            {\n                // Unlock, render, and relock the vertex buffer\n                m_pVB->Unlock();\n                m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );\n                m_pVB->Lock( 0, 0, (void**)&pVertices, D3DLOCK_DISCARD );\n                dwNumTriangles = 0L;\n            }\n        }\n\n        x += w - (2 * m_dwSpacing) / 10.0f;\n    }\n\n    // Unlock and render the vertex buffer\n    m_pVB->Unlock();\n    if( dwNumTriangles > 0 )\n        m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, 0, dwNumTriangles );\n\n    // Restore the modified renderstates\n    m_pStateBlockSaved->Apply();\n\n    return S_OK;\n}\n\n\n\n\n"
  },
  {
    "path": "Player/D3DFONT.H",
    "content": "//-----------------------------------------------------------------------------\n// File: D3DFont.h\n//\n// Desc: Texture-based font class\n//-----------------------------------------------------------------------------\n#ifndef D3DFONT_H\n#define D3DFONT_H\n#include <tchar.h>\n#include <D3D9.h>\n\n\n// Font creation flags\n#define D3DFONT_BOLD        0x0001\n#define D3DFONT_ITALIC      0x0002\n#define D3DFONT_ZENABLE     0x0004\n\n// Font rendering flags\n#define D3DFONT_CENTERED_X  0x0001\n#define D3DFONT_CENTERED_Y  0x0002\n#define D3DFONT_TWOSIDED    0x0004\n#define D3DFONT_FILTERED    0x0008\n\n\n\n\n//-----------------------------------------------------------------------------\n// Name: class CD3DFont\n// Desc: Texture-based font class for doing text in a 3D scene.\n//-----------------------------------------------------------------------------\nclass CD3DFont\n{\n    TCHAR   m_strFontName[80];            // Font properties\n    DWORD   m_dwFontHeight;\n    DWORD   m_dwFontFlags;\n\n    LPDIRECT3DDEVICE9       m_pd3dDevice; // A D3DDevice used for rendering\n    LPDIRECT3DTEXTURE9      m_pTexture;   // The d3d texture for this font\n    LPDIRECT3DVERTEXBUFFER9 m_pVB;        // VertexBuffer for rendering text\n    DWORD   m_dwTexWidth {};                 // Texture dimensions\n    DWORD   m_dwTexHeight {};\n    FLOAT   m_fTextScale {};\n    FLOAT   m_fTexCoords[128 - 32][4] {};\n    DWORD   m_dwSpacing;                  // Character pixel spacing per side\n\n    // Stateblocks for setting and restoring render states\n    LPDIRECT3DSTATEBLOCK9 m_pStateBlockSaved;\n    LPDIRECT3DSTATEBLOCK9 m_pStateBlockDrawText;\n\npublic:\n    // 2D and 3D text drawing functions\n    HRESULT DrawText( FLOAT x, FLOAT y, DWORD dwColor, \n                      const TCHAR* strText, DWORD dwFlags=0L );\n    HRESULT DrawTextScaled( FLOAT x, FLOAT y, FLOAT z, \n                            FLOAT fXScale, FLOAT fYScale, DWORD dwColor, \n                            const TCHAR* strText, DWORD dwFlags=0L );\n    HRESULT Render3DText( const TCHAR* strText, DWORD dwFlags=0L );\n    \n    // Function to get extent of text\n    HRESULT GetTextExtent( const TCHAR* strText, SIZE* pSize );\n\n    // Initializing and destroying device-dependent objects\n    HRESULT InitDeviceObjects( LPDIRECT3DDEVICE9 pd3dDevice );\n    HRESULT RestoreDeviceObjects();\n    HRESULT InvalidateDeviceObjects();\n    HRESULT DeleteDeviceObjects();\n\n    // Constructor / destructor\n    CD3DFont( const TCHAR* strFontName, DWORD dwHeight, DWORD dwFlags=0L );\n    ~CD3DFont();\n};\n\n\n\n\n#endif\n\n\n"
  },
  {
    "path": "Player/DialogBarPlayerControl.cpp",
    "content": "// DialogBarPlayerControl.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n#include \"Player.h\"\n#include \"DialogBarPlayerControl.h\"\n\n#include \"MainFrm.h\"\n#include \"PlayerDoc.h\"\n#include \"MakeDelegate.h\"\n#include \"SecondsToString.h\"\n\n#include <algorithm>\n#include <string>\n\n\n#ifdef _DEBUG\n#define new DEBUG_NEW\n#endif\n\nenum { RANGE_MAX = 0x7FFF };\n\nenum { WM_SET_TIME = WM_USER + 101 };\n\nnamespace {\n\nHICON LoadIcon(int idr, int iconSize)\n{\n    return (HICON) LoadImage(\n        AfxGetApp()->m_hInstance,\n        MAKEINTRESOURCE(idr),\n        IMAGE_ICON,\n        iconSize, iconSize, // use actual size\n        LR_DEFAULTCOLOR);\n}\n\ndouble GetValueByMouseClick(CWnd* pDlg, CSliderCtrl* pSliderCtrl)\n{\n    CRect   rectClient, rectChannel, rectThumb;\n    pDlg->GetClientRect(rectClient);\n    pSliderCtrl->GetChannelRect(rectChannel);\n    pSliderCtrl->GetThumbRect(rectThumb);\n    rectChannel.DeflateRect(rectThumb.Width() / 2, 0);\n    CPoint mousePt(AfxGetCurrentMessage()->pt);\n    pSliderCtrl->ScreenToClient(&mousePt);\n    return std::clamp(\n        double(mousePt.x - rectClient.left - rectChannel.left) /\n        (rectChannel.right - rectChannel.left),\n        0., 1.);\n}\n\n}\n\n\n// CDialogBarPlayerControl\n\nIMPLEMENT_DYNAMIC(CDialogBarPlayerControl, CPaneDialog)\n\nCDialogBarPlayerControl::CDialogBarPlayerControl()\n: m_pDoc(nullptr)\n, m_hPlay(NULL)\n, m_hPause(NULL)\n, m_hAudio(NULL)\n, m_hAudioOff(NULL)\n, m_hFullScreen(NULL)\n, m_savedVolume(0)\n, m_oldTotalTime(-1) // unset\n, m_oldCurrentTime(-1) // unset\n, m_tracking(false)\n, m_selStart(0)\n, m_selEnd(RANGE_MAX)\n{\n    CDialogTemplate dlgtemplate;\n    if (dlgtemplate.Load(MAKEINTRESOURCE(IDD)))\n    {\n        CSize size;\n        dlgtemplate.GetSizeInPixels(&size);\n        SetMinSize(size);\n    }\n}\n\nCDialogBarPlayerControl::~CDialogBarPlayerControl()\n{\n    onDocDetaching();\n}\n\nvoid CDialogBarPlayerControl::onDocDetaching()\n{\n    if (m_pDoc)\n    {\n        m_pDoc->framePositionChanged.disconnect(MAKE_DELEGATE(&CDialogBarPlayerControl::onFramePositionChanged, this));\n        m_pDoc->totalTimeUpdated.disconnect(MAKE_DELEGATE(&CDialogBarPlayerControl::onTotalTimeUpdated, this));\n        m_pDoc->currentTimeUpdated.disconnect(MAKE_DELEGATE(&CDialogBarPlayerControl::onCurrentTimeUpdated, this));\n\n        m_pDoc->rangeStartTimeChanged.disconnect(MAKE_DELEGATE(&CDialogBarPlayerControl::onRangeStartTimeChanged, this));\n        m_pDoc->rangeEndTimeChanged.disconnect(MAKE_DELEGATE(&CDialogBarPlayerControl::onRangeEndTimeChanged, this));\n\n        m_pDoc->onDestructing.disconnect(MAKE_DELEGATE(&CDialogBarPlayerControl::onDocDetaching, this));\n\n        m_pDoc = nullptr;\n    }\n}\n\n\nvoid CDialogBarPlayerControl::DoDataExchange(CDataExchange* pDX)\n{\n    __super::DoDataExchange(pDX);\n    //{{AFX_DATA_MAP(CDialogBarPlayerControl)\n    // NOTE: the ClassWizard will add DDX and DDV calls here\n    //}}AFX_DATA_MAP\n    DDX_Control(pDX, IDC_PROGRESS_SLIDER, m_progressSlider);\n    DDX_Control(pDX, IDC_VOLUME_SLIDER, m_volumeSlider);\n}\n\n\nBEGIN_MESSAGE_MAP(CDialogBarPlayerControl, CPaneDialog)\n    ON_WM_HSCROLL()\n    ON_UPDATE_COMMAND_UI(IDC_PLAY_PAUSE, &CDialogBarPlayerControl::OnUpdatePlayPause)\n    ON_UPDATE_COMMAND_UI(IDC_AUDIO_ON_OFF, &CDialogBarPlayerControl::OnUpdateAudioOnOff)\n    ON_BN_CLICKED(IDC_PLAY_PAUSE, &CDialogBarPlayerControl::OnClickedPlayPause)\n    ON_BN_CLICKED(IDC_AUDIO_ON_OFF, &CDialogBarPlayerControl::OnClickedAudioOnOff)\n    ON_MESSAGE(WM_SET_TIME, &CDialogBarPlayerControl::OnSetTime)\n    ON_MESSAGE(WM_INITDIALOG, &CDialogBarPlayerControl::HandleInitDialog)\n    ON_UPDATE_COMMAND_UI(IDC_FRAME_STEP, &CDialogBarPlayerControl::OnUpdateFrameStep)\n    ON_UPDATE_COMMAND_UI(IDC_VOLUME_SLIDER, &CDialogBarPlayerControl::OnUpdateVolumeSlider)\n    ON_UPDATE_COMMAND_UI(IDC_CURRENT_TIME, &CDialogBarPlayerControl::OnUpdateCurrentTime)\n    END_MESSAGE_MAP()\n\n\n\n// CDialogBarPlayerControl message handlers\n\nLRESULT CDialogBarPlayerControl::HandleInitDialog(WPARAM wParam, LPARAM lParam)\n{\n    __super::HandleInitDialog(wParam, lParam);\n\n    CRect btnRect;\n    GetDlgItem(IDC_PLAY_PAUSE)->GetClientRect(btnRect);\n    const int iconSizeLimit = min(btnRect.Width() - 2 * GetSystemMetrics(SM_CXBORDER),\n        btnRect.Height() - 2 * GetSystemMetrics(SM_CYBORDER)) * 4 / 5;\n\n    const int iconSize = min(iconSizeLimit & ((iconSizeLimit > 32)? ~15 : ~7), 48);\n\n    m_hPlay = LoadIcon(IDI_PLAY, iconSize);\n    m_hPause = LoadIcon(IDI_PAUSE, iconSize);\n    m_hAudio = LoadIcon(IDI_AUDIO, iconSize);\n    m_hAudioOff = LoadIcon(IDI_AUDIO_OFF, iconSize);\n    m_hFullScreen = LoadIcon(IDI_FULL_SCREEN, iconSize);\n\n    static_cast<CButton*>(GetDlgItem(IDC_PLAY_PAUSE))->SetIcon(m_hPlay);\n    static_cast<CButton*>(GetDlgItem(IDC_AUDIO_ON_OFF))->SetIcon(m_hAudio);\n    static_cast<CButton*>(GetDlgItem(IDC_FULL_SCREEN))->SetIcon(m_hFullScreen);\n\n    m_progressSlider.SetRange(0, RANGE_MAX);\n    m_progressSlider.SetPageSize(0);\n    m_progressSlider.ModifyStyle(0, TBS_ENABLESELRANGE);\n    m_volumeSlider.SetRange(0, RANGE_MAX);\n    m_volumeSlider.SetPos(RANGE_MAX);\n    m_volumeSlider.SetPageSize(0);\n\n    return TRUE;\n}\n\nvoid CDialogBarPlayerControl::setDocument(CPlayerDoc* pDoc)\n{\n    ASSERT(!m_pDoc);\n    m_pDoc = pDoc;\n\n    m_volumeSlider.SetPos(int(RANGE_MAX * pDoc->soundVolume()));\n\n    m_pDoc->framePositionChanged.connect(MAKE_DELEGATE(&CDialogBarPlayerControl::onFramePositionChanged, this));\n    m_pDoc->totalTimeUpdated.connect(MAKE_DELEGATE(&CDialogBarPlayerControl::onTotalTimeUpdated, this));\n    m_pDoc->currentTimeUpdated.connect(MAKE_DELEGATE(&CDialogBarPlayerControl::onCurrentTimeUpdated, this));\n\n    m_pDoc->rangeStartTimeChanged.connect(MAKE_DELEGATE(&CDialogBarPlayerControl::onRangeStartTimeChanged, this));\n    m_pDoc->rangeEndTimeChanged.connect(MAKE_DELEGATE(&CDialogBarPlayerControl::onRangeEndTimeChanged, this));\n\n    m_pDoc->onDestructing.connect(MAKE_DELEGATE(&CDialogBarPlayerControl::onDocDetaching, this));\n}\n\nvoid CDialogBarPlayerControl::onFramePositionChanged(long long frame, long long total)\n{\n    if (!m_tracking)\n    {\n        ASSERT(total >= 0);\n        const int pos = (total > 0)? int((frame * RANGE_MAX) / total) : 0;\n        m_progressSlider.SendNotifyMessage(TBM_SETPOS, TRUE, pos);\n    }\n}\n\nenum { MIN_SEL_WIDTH = 50 };\n\nvoid CDialogBarPlayerControl::onRangeStartTimeChanged(long long frame, long long total)\n{\n    ASSERT(total >= 0);\n    const int pos = (total > 0) ? int((frame * (RANGE_MAX - MIN_SEL_WIDTH)) / total) : 0;\n    m_selStart = pos;\n    m_progressSlider.SendNotifyMessage(TBM_SETSEL, TRUE, MAKELPARAM(pos, m_selEnd));\n}\n\nvoid CDialogBarPlayerControl::onRangeEndTimeChanged(long long frame, long long total)\n{\n    ASSERT(total >= 0);\n    const int pos = (total > 0) ? int((frame * (RANGE_MAX - MIN_SEL_WIDTH)) / total) + MIN_SEL_WIDTH : 0;\n    m_selEnd = pos;\n    m_progressSlider.SendNotifyMessage(TBM_SETSEL, TRUE, MAKELPARAM(m_selStart, pos));\n}\n\nvoid CDialogBarPlayerControl::onTotalTimeUpdated(double secs)\n{\n    int totalTime = int(secs * 1000);\n    if (totalTime == m_oldTotalTime)\n        return;\n\n    m_oldTotalTime = totalTime;\n\n    SendNotifyMessage(WM_SET_TIME, IDC_TOTAL_TIME, totalTime);\n}\n\nvoid CDialogBarPlayerControl::onCurrentTimeUpdated(double secs)\n{\n    int currentTime = int(secs * 1000);\n    const bool notify = (currentTime / 1000 != m_oldCurrentTime / 1000) ||\n                        m_pDoc && m_pDoc->isPaused() && currentTime != m_oldCurrentTime;\n\n    m_oldCurrentTime = currentTime;\n\n    if (notify)\n        SendNotifyMessage(WM_SET_TIME, IDC_CURRENT_TIME, currentTime);\n}\n\nLRESULT CDialogBarPlayerControl::OnSetTime(WPARAM wParam, LPARAM lParam)\n{\n    const bool milli = wParam == IDC_CURRENT_TIME && m_pDoc && m_pDoc->isPaused();\n    SetDlgItemText(wParam, secondsToString(lParam, milli).c_str());\n    return 0;\n}\n\nvoid CDialogBarPlayerControl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)\n{\n    if (m_pDoc)\n    {\n        if (static_cast<CWnd*>(pScrollBar) == &m_progressSlider)\n        {\n            switch (nSBCode)\n            {\n                case SB_LINELEFT:\n                    if (m_pDoc->isPaused())\n                    {\n                        m_pDoc->prevFrame();\n                    }\n                    break;\n                case SB_LINERIGHT:\n                    if (m_pDoc->isPaused())\n                    {\n                        m_pDoc->nextFrame();\n                    }\n                    break;\n\n                case SB_PAGELEFT: \n                case SB_PAGERIGHT:\n                    m_pDoc->seekByPercent(GetValueByMouseClick(this, &m_progressSlider));\n                    break;\n\n                case SB_THUMBTRACK:\n                    m_pDoc->seekByPercent(m_progressSlider.GetPos() / double(RANGE_MAX));\n                    m_tracking = true;\n                    break;\n\n                case SB_RIGHT:\n                    m_pDoc->seekToEnd();\n                    break;\n\n                case SB_ENDSCROLL:\n                    m_tracking = false;\n                    break;\n            }\n        }\n        else if (static_cast<CWnd*>(pScrollBar) == &m_volumeSlider)\n        {\n            if (nSBCode == SB_PAGELEFT || nSBCode == SB_PAGERIGHT)\n            {\n                const double valueByMouseClick = GetValueByMouseClick(this, &m_volumeSlider);\n                m_volumeSlider.SetPos(int(valueByMouseClick * RANGE_MAX));\n                m_pDoc->setVolume(valueByMouseClick);\n            }\n            else\n            {\n                m_pDoc->setVolume(m_volumeSlider.GetPos() / double(RANGE_MAX));\n            }\n        }\n    }\n\n    __super::OnHScroll(nSBCode, nPos, pScrollBar);\n}\n\n\nvoid CDialogBarPlayerControl::OnUpdatePlayPause(CCmdUI *pCmdUI)\n{\n    if (m_pDoc)\n    {\n        pCmdUI->Enable(m_pDoc->isPlaying());\n        if (pCmdUI->m_pOther)\n        {\n            static_cast<CButton*>(pCmdUI->m_pOther)->SetIcon(\n                m_pDoc->isPaused() ? m_hPlay : m_hPause);\n        }\n    }\n}\n\nvoid CDialogBarPlayerControl::OnUpdateAudioOnOff(CCmdUI *pCmdUI)\n{\n    if (m_pDoc)\n    {\n        pCmdUI->Enable(m_pDoc->isPlaying());\n        if (pCmdUI->m_pOther)\n        {\n            static_cast<CButton*>(pCmdUI->m_pOther)->SetIcon(\n                (m_volumeSlider.GetPos() > 0) ? m_hAudio : m_hAudioOff);\n        }\n    }\n\n}\n\nvoid CDialogBarPlayerControl::OnClickedPlayPause()\n{\n    if (m_pDoc)\n    {\n        if (m_pDoc->isPaused() && IsDlgButtonChecked(IDC_FRAME_STEP))\n        {\n            if (GetKeyState(VK_SHIFT) < 0)\n                m_pDoc->prevFrame();\n            else\n                m_pDoc->nextFrame();\n        }\n        else\n        {\n            m_pDoc->pauseResume();\n        }\n    }\n}\n\n\nvoid CDialogBarPlayerControl::OnClickedAudioOnOff()\n{\n    int newVolume;\n    if (m_savedVolume)\n    {\n        newVolume = m_savedVolume;\n        m_savedVolume = 0;\n    }\n    else\n    {\n        m_savedVolume = m_volumeSlider.GetPos();\n        newVolume = 0;\n    }\n\n    m_volumeSlider.SetPos(newVolume);\n    m_pDoc->setVolume(newVolume / double(RANGE_MAX));\n}\n\n\nvoid CDialogBarPlayerControl::OnUpdateFrameStep(CCmdUI *pCmdUI)\n{\n    if (pCmdUI->m_pOther)\n    {\n        pCmdUI->m_pOther->ShowWindow(\n            (m_pDoc && m_pDoc->isPaused()) ? SW_SHOWNA : SW_HIDE);\n    }\n}\n\n\nvoid CDialogBarPlayerControl::OnUpdateVolumeSlider(CCmdUI *pCmdUI)\n{\n    if (pCmdUI->m_pOther)\n    {\n        pCmdUI->m_pOther->ShowWindow(\n            (m_pDoc && m_pDoc->isPaused()) ? SW_HIDE : SW_SHOWNA);\n    }\n}\n\nvoid CDialogBarPlayerControl::OnUpdateCurrentTime(CCmdUI* pCmdUI)\n{\n    if (pCmdUI->m_pOther && m_pDoc && m_pDoc->isPaused())\n    {\n        pCmdUI->m_pOther->SetWindowText(secondsToString(m_oldCurrentTime, true).c_str());\n    }\n}\n"
  },
  {
    "path": "Player/DialogBarPlayerControl.h",
    "content": "#pragma once\n\n#include \"afxcmn.h\"\n\nclass CPlayerDoc;\n\n// CDialogBarPlayerControl\n\nclass CDialogBarPlayerControl\n    : public CPaneDialog\n{\n    DECLARE_DYNAMIC(CDialogBarPlayerControl)\n\npublic:\n    CDialogBarPlayerControl();\n    virtual ~CDialogBarPlayerControl();\n\n    // Dialog Data\n    //{{AFX_DATA(CDialogBarPlayerControl)\n    enum { IDD = IDD_DIALOGBAR_PLAYER_CONTROL };\n    // NOTE: the ClassWizard will add data members here\n    //}}AFX_DATA\n\n    void setDocument(CPlayerDoc* pDoc);\n\n    // Overrides\n    // ClassWizard generated virtual function overrides\n    //{{AFX_VIRTUAL(CDialogBarPlayerControl)\nprotected:\n    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support\n    //}}AFX_VIRTUAL\n\n    int GetCaptionHeight() const override { return 0; }\n\n    void onFramePositionChanged(long long frame, long long total);\n    void onTotalTimeUpdated(double secs);\n    void onCurrentTimeUpdated(double secs);\n\n    void onRangeStartTimeChanged(long long frame, long long total);\n    void onRangeEndTimeChanged(long long frame, long long total);\n\n    void onDocDetaching();\n\nprotected:\n    DECLARE_MESSAGE_MAP()\n    afx_msg LRESULT HandleInitDialog(WPARAM wParam, LPARAM lParam);\n    afx_msg LRESULT OnSetTime(WPARAM wParam, LPARAM lParam);\npublic:\n\nprivate:\n    CPlayerDoc* m_pDoc;\n    HICON m_hPlay;\n    HICON m_hPause;\n    HICON m_hAudio;\n    HICON m_hAudioOff;\n    HICON m_hFullScreen;\n    int m_savedVolume;\n    volatile int m_oldTotalTime;\n    volatile int m_oldCurrentTime;\n    bool m_tracking;\n\n    int m_selStart;\n    int m_selEnd;\n\npublic:\n    CSliderCtrl m_progressSlider;\n    CSliderCtrl m_volumeSlider;\n    afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);\n    afx_msg void OnUpdatePlayPause(CCmdUI *pCmdUI);\n    afx_msg void OnUpdateAudioOnOff(CCmdUI *pCmdUI);\n    afx_msg void OnClickedPlayPause();\n    afx_msg void OnClickedAudioOnOff();\n    afx_msg void OnUpdateFrameStep(CCmdUI *pCmdUI);\n    afx_msg void OnUpdateVolumeSlider(CCmdUI *pCmdUI);\n    afx_msg void OnUpdateCurrentTime(CCmdUI *pCmdUI);\n};\n\n\n"
  },
  {
    "path": "Player/DialogBarRange.cpp",
    "content": "// DialogBarRange.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n#include \"Player.h\"\n#include \"DialogBarRange.h\"\n\n#include \"PlayerDoc.h\"\n\n#include \"MakeDelegate.h\"\n\n\nconst WCHAR szwReset[] = { 0x29BB, 0 };\n\n// CDialogBarRange\n\nIMPLEMENT_DYNAMIC(CDialogBarRange, CPaneDialog)\n\nCDialogBarRange::CDialogBarRange()\n: m_pDoc(nullptr)\n{\n    CDialogTemplate dlgtemplate;\n    if (dlgtemplate.Load(MAKEINTRESOURCE(IDD)))\n    {\n        CSize size;\n        dlgtemplate.GetSizeInPixels(&size);\n        SetMinSize(size);\n    }\n}\n\nCDialogBarRange::~CDialogBarRange()\n{\n    onDocDetaching();\n}\n\nvoid CDialogBarRange::onDocDetaching()\n{\n    if (m_pDoc)\n    {\n        m_pDoc->totalTimeUpdated.disconnect(MAKE_DELEGATE(&CDialogBarRange::onTotalTimeUpdated, this));\n        m_pDoc->onDestructing.disconnect(MAKE_DELEGATE(&CDialogBarRange::onDocDetaching, this));\n\n        m_pDoc = nullptr;\n    }\n}\n\nvoid CDialogBarRange::setDocument(CPlayerDoc* pDoc)\n{\n    ASSERT(!m_pDoc);\n    m_pDoc = pDoc;\n\n    m_pDoc->totalTimeUpdated.connect(MAKE_DELEGATE(&CDialogBarRange::onTotalTimeUpdated, this));\n    m_pDoc->onDestructing.connect(MAKE_DELEGATE(&CDialogBarRange::onDocDetaching, this));\n}\n\nvoid CDialogBarRange::DoDataExchange(CDataExchange* pDX)\n{\n    __super::DoDataExchange(pDX);\n    //{{AFX_DATA_MAP(CDialogBarRange)\n    // NOTE: the ClassWizard will add DDX and DDV calls here\n    //}}AFX_DATA_MAP\n    DDX_Control(pDX, IDC_EDIT_START, m_startTime);\n    DDX_Control(pDX, IDC_EDIT_END, m_endTime);\n}\n\nBEGIN_MESSAGE_MAP(CDialogBarRange, CPaneDialog)\n    ON_COMMAND(IDC_START, &CDialogBarRange::OnStart)\n    ON_COMMAND(IDC_START_RESET, &CDialogBarRange::OnStartReset)\n    ON_COMMAND(IDC_END, &CDialogBarRange::OnEnd)\n    ON_COMMAND(IDC_END_RESET, &CDialogBarRange::OnEndReset)\n    ON_UPDATE_COMMAND_UI(IDC_START, &CDialogBarRange::OnUpdateStart)\n    ON_UPDATE_COMMAND_UI(IDC_START_RESET, &CDialogBarRange::OnUpdateStartReset)\n    ON_UPDATE_COMMAND_UI(IDC_END, &CDialogBarRange::OnUpdateEnd)\n    ON_UPDATE_COMMAND_UI(IDC_END_RESET, &CDialogBarRange::OnUpdateEndReset)\n    ON_UPDATE_COMMAND_UI(ID_FILE_SAVE_COPY_AS, &CDialogBarRange::OnUpdateSave)\n    ON_EN_CHANGE(IDC_EDIT_START, &CDialogBarRange::OnChangeStart)\n    ON_EN_CHANGE(IDC_EDIT_END, &CDialogBarRange::OnChangeEnd)\n    ON_BN_CLICKED(IDC_LOSSLESS_CUT, &CDialogBarRange::OnBnClickedLosslessCut)\n    ON_MESSAGE(WM_INITDIALOG, &CDialogBarRange::HandleInitDialog)\nEND_MESSAGE_MAP()\n\nLRESULT CDialogBarRange::HandleInitDialog(WPARAM wParam, LPARAM lParam)\n{\n    __super::HandleInitDialog(wParam, lParam);\n\n    if (auto control = static_cast<CButton*>(GetDlgItem(IDC_LOSSLESS_CUT)))\n    {\n        control->SetCheck(BST_CHECKED);\n    }\n\n    CRect rect(0, 0, 12, 12);\n    MapDialogRect(*this, &rect);\n\n    // Create the font with the calculated size\n    m_font.CreateFont(\n        rect.Height(),                     // Height\n        0,                          // Width\n        0,                          // Escapement\n        0,                          // Orientation\n        FW_MEDIUM,                    // Weight\n        FALSE,                      // Italic\n        FALSE,                      // Underline\n        0,                          // StrikeOut\n        ANSI_CHARSET,               // CharSet\n        OUT_DEFAULT_PRECIS,         // OutPrecision\n        CLIP_DEFAULT_PRECIS,        // ClipPrecision\n        DEFAULT_QUALITY,            // Quality\n        DEFAULT_PITCH | FF_SWISS,   // PitchAndFamily\n        _T(\"Arial\"));               // Facename\n\n    for (auto id : {IDC_START_RESET, IDC_END_RESET})\n    {\n        if (auto control = static_cast<CButton*>(GetDlgItem(id)))\n        {\n            control->SetFont(&m_font);\n            control->SetWindowText(szwReset);\n        }\n    }\n\n    return TRUE;\n}\n\nvoid CDialogBarRange::onTotalTimeUpdated(double)\n{\n\tm_startTime.Reset();\n\tm_endTime.Reset();\n}\n\n\n// CDialogBarRange message handlers\n\n\nvoid CDialogBarRange::OnStart()\n{\n    const double currentTime = m_pDoc->getCurrentTime();\n    m_pDoc->setRangeStartTime(currentTime);\n    m_startTime.SetValue(currentTime);\n}\n\n\nvoid CDialogBarRange::OnStartReset()\n{\n\tm_pDoc->setRangeStartTime(m_pDoc->getStartTime());\n\tm_startTime.Reset();\n}\n\n\nvoid CDialogBarRange::OnEnd()\n{\n    const double currentTime = m_pDoc->getCurrentTime();\n    m_pDoc->setRangeEndTime(currentTime);\n    m_endTime.SetValue(currentTime);\n}\n\n\nvoid CDialogBarRange::OnEndReset()\n{\n\tm_pDoc->setRangeEndTime(m_pDoc->getEndTime());\n\tm_endTime.Reset();\n}\n\n\nvoid CDialogBarRange::OnUpdateStart(CCmdUI *pCmdUI)\n{\n    pCmdUI->Enable(m_pDoc->isPlaying());\n}\n\n\nvoid CDialogBarRange::OnUpdateStartReset(CCmdUI *pCmdUI)\n{\n    pCmdUI->Enable(m_pDoc->isPlaying());\n}\n\n\nvoid CDialogBarRange::OnUpdateEnd(CCmdUI *pCmdUI)\n{\n    pCmdUI->Enable(m_pDoc->isPlaying());\n}\n\n\nvoid CDialogBarRange::OnUpdateEndReset(CCmdUI *pCmdUI)\n{\n    pCmdUI->Enable(m_pDoc->isPlaying());\n}\n\n\nvoid CDialogBarRange::OnUpdateSave(CCmdUI *pCmdUI)\n{\n    pCmdUI->Enable(m_pDoc->isPlaying());\n}\n\nvoid CDialogBarRange::OnChangeStart()\n{\n    m_pDoc->setRangeStartTime(\n        m_startTime.IsEmpty()? m_pDoc->getStartTime() : m_startTime.GetValue());\n}\n\nvoid CDialogBarRange::OnChangeEnd()\n{\n    m_pDoc->setRangeEndTime(\n        m_endTime.IsEmpty()? m_pDoc->getEndTime() : m_endTime.GetValue());\n}\n\n\nvoid CDialogBarRange::OnBnClickedLosslessCut()\n{\n    if (auto control = static_cast<CButton*>(GetDlgItem(IDC_LOSSLESS_CUT)))\n    {\n        m_pDoc->setLosslessCut(control->GetCheck() != BST_UNCHECKED);\n    }\n}\n"
  },
  {
    "path": "Player/DialogBarRange.h",
    "content": "#pragma once\n\n#include \"EditTime.h\"\n\nclass CPlayerDoc;\n\n// CDialogBarRange\n\nclass CDialogBarRange : public CPaneDialog\n{\n\tDECLARE_DYNAMIC(CDialogBarRange)\n\npublic:\n\tCDialogBarRange();\n\tvirtual ~CDialogBarRange();\n\n    enum { IDD = IDD_DIALOGBAR_RANGE };\n\n    void setDocument(CPlayerDoc* pDoc);\n\n    // Overrides\n    // ClassWizard generated virtual function overrides\n    //{{AFX_VIRTUAL(CDialogBarPlayerControl)\nprotected:\n    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support\n    //}}AFX_VIRTUAL\n\nprotected:\n    int GetCaptionHeight() const override { return 0; }\n\n\tvoid onTotalTimeUpdated(double secs);\n\n    void onDocDetaching();\n\nprotected:\n\tDECLARE_MESSAGE_MAP()\n    afx_msg LRESULT HandleInitDialog(WPARAM wParam, LPARAM lParam);\nprivate:\n    CPlayerDoc* m_pDoc;\n    CFont m_font;\npublic:\n    CEditTime m_startTime;\n    CEditTime m_endTime;\n    afx_msg void OnStart();\n    afx_msg void OnStartReset();\n    afx_msg void OnEnd();\n    afx_msg void OnEndReset();\n    afx_msg void OnUpdateStart(CCmdUI *pCmdUI);\n    afx_msg void OnUpdateStartReset(CCmdUI *pCmdUI);\n    afx_msg void OnUpdateEnd(CCmdUI *pCmdUI);\n    afx_msg void OnUpdateEndReset(CCmdUI *pCmdUI);\n    afx_msg void OnUpdateSave(CCmdUI *pCmdUI);\n    afx_msg void OnChangeStart();\n    afx_msg void OnChangeEnd();\n    afx_msg void OnBnClickedLosslessCut();\n};\n"
  },
  {
    "path": "Player/DialogOpenURL.cpp",
    "content": "// DialogOpenURL.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n#include \"Player.h\"\n#include \"DialogOpenURL.h\"\n#include \"afxdialogex.h\"\n\n\n// CDialogOpenURL dialog\n\nIMPLEMENT_DYNAMIC(CDialogOpenURL, CDialog)\n\nCDialogOpenURL::CDialogOpenURL(CWnd* pParent /*=NULL*/)\n\t: CDialog(IDD_DIALOG_OPEN_URL, pParent)\n    , m_URL(_T(\"\"))\n    , m_bParse(false)\n    , m_inputFormt(_T(\"\"))\n{\n\n}\n\nCDialogOpenURL::~CDialogOpenURL()\n{\n}\n\nvoid CDialogOpenURL::DoDataExchange(CDataExchange* pDX)\n{\n    CDialog::DoDataExchange(pDX);\n    DDX_Text(pDX, IDC_EDIT_URL, m_URL);\n    DDX_Check(pDX, IDC_PARSE, m_bParse);\n    DDX_Text(pDX, IDC_EDIT_INPUT_FORMAT, m_inputFormt);\n}\n\n\nBEGIN_MESSAGE_MAP(CDialogOpenURL, CDialog)\nEND_MESSAGE_MAP()\n\n\n// CDialogOpenURL message handlers\n"
  },
  {
    "path": "Player/DialogOpenURL.h",
    "content": "#pragma once\n\n\n// CDialogOpenURL dialog\n\nclass CDialogOpenURL : public CDialog\n{\n\tDECLARE_DYNAMIC(CDialogOpenURL)\n\npublic:\n\texplicit CDialogOpenURL(CWnd* pParent = NULL);   // standard constructor\n\tvirtual ~CDialogOpenURL();\n\n// Dialog Data\n#ifdef AFX_DESIGN_TIME\n\tenum { IDD = IDD_DIALOG_OPEN_URL };\n#endif\n\nprotected:\n\tvirtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support\n\n\tDECLARE_MESSAGE_MAP()\npublic:\n    CString m_URL;\n    int m_bParse{};\n    CString m_inputFormt;\n};\n"
  },
  {
    "path": "Player/DialogVideoFilter.cpp",
    "content": "// DialogVideoFilter.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n#include \"Player.h\"\n#include \"afxdialogex.h\"\n#include \"DialogVideoFilter.h\"\n\n\n// CDialogVideoFilter dialog\n\nIMPLEMENT_DYNAMIC(CDialogVideoFilter, CDialog)\n\nCDialogVideoFilter::CDialogVideoFilter(CWnd* pParent /*=nullptr*/)\n\t: CDialog(IDD_DIALOG_VIDEO_FILTER, pParent)\n    , m_videoFilter(_T(\"\"))\n    , m_enableVideoFilter(FALSE)\n{\n\n}\n\nCDialogVideoFilter::~CDialogVideoFilter()\n{\n}\n\nvoid CDialogVideoFilter::DoDataExchange(CDataExchange* pDX)\n{\n    CDialog::DoDataExchange(pDX);\n    DDX_Text(pDX, IDC_VIDEO_FILTER, m_videoFilter);\n    DDX_Check(pDX, IDC_ENABLE_VIDEO_FILTER, m_enableVideoFilter);\n}\n\n\nBEGIN_MESSAGE_MAP(CDialogVideoFilter, CDialog)\nEND_MESSAGE_MAP()\n\n\n// CDialogVideoFilter message handlers\n"
  },
  {
    "path": "Player/DialogVideoFilter.h",
    "content": "#pragma once\n#include \"afxdialogex.h\"\n\n\n// CDialogVideoFilter dialog\n\nclass CDialogVideoFilter : public CDialog\n{\n\tDECLARE_DYNAMIC(CDialogVideoFilter)\n\npublic:\n\tCDialogVideoFilter(CWnd* pParent = nullptr);   // standard constructor\n\tvirtual ~CDialogVideoFilter();\n\n// Dialog Data\n#ifdef AFX_DESIGN_TIME\n\tenum { IDD = IDD_DIALOG_VIDEO_FILTER };\n#endif\n\nprotected:\n\tvirtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support\n\n\tDECLARE_MESSAGE_MAP()\npublic:\n    CString m_videoFilter;\n    BOOL m_enableVideoFilter;\n};\n"
  },
  {
    "path": "Player/EditTime.cpp",
    "content": "// EditTime.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n#include \"EditTime.h\"\n#include \"SecondsToString.h\"\n\n#include <cmath>\n\n#ifdef _DEBUG\n#define new DEBUG_NEW\n#undef THIS_FILE\nstatic char THIS_FILE[] = __FILE__;\n#endif\n\nnamespace {\n\n\nenum\n{\n    TIME_INVALID = -1000000000\n};\n\nint ReadUint(const TCHAR*& s)\n{\n    int buf = 0;\n    for (; *s >= '0' && *s <= '9'; ++s) \n        buf = buf * 10 + *s - '0';\n\n    return buf;\n}\n\ndouble ParseTime(const TCHAR* timeStr)\n{\n    int seconds = 0;\n\n    int numDelims = 0;\n\n    const bool minus = *timeStr == '-';\n    if (minus)\n        ++timeStr;\n\n    for (;;)\n    {\n        switch (*timeStr)\n        {\n        case '\\0':\n            return minus ? -seconds : seconds;\n        case ':':\n            if (++numDelims > 2)\n                return TIME_INVALID;\n            seconds *= 60;\n            ++timeStr;\n            break;\n        case '.':\n        {\n            ++timeStr;\n            const auto prevPtr = timeStr;\n            const auto millis = ReadUint(timeStr);\n            if (*timeStr != '\\0')\n                return TIME_INVALID;\n            const int msecStringLen = timeStr - prevPtr;\n            if (msecStringLen > 3)\n                return TIME_INVALID;\n            if (msecStringLen == 0)\n                return minus ? -seconds : seconds;\n            const auto absResult = seconds + millis / std::pow(10, msecStringLen);\n            return minus ? -absResult : absResult;\n        }\n        break;\n        default:\n            const auto prevPtr = timeStr;\n            seconds += ReadUint(timeStr);\n            if (prevPtr == timeStr)\n                return TIME_INVALID;\n        }\n    }\n}\n\nbool Match(const TCHAR* timeStr)\n{ \n    return ParseTime(timeStr) != TIME_INVALID; \n}\n\n} // namespace\n\n\nenum { WM_RESET = WM_USER + 101 };\n\n/////////////////////////////////////////////////////////////////////////////\n// CEditTime\n\nCEditTime::CEditTime()\n{\n}\n\nCEditTime::~CEditTime()\n{\n}\n\nBEGIN_MESSAGE_MAP(CEditTime, CEdit)\n    //{{AFX_MSG_MAP(CEditTime)\n    ON_WM_CHAR()\n    ON_MESSAGE(WM_RESET, &CEditTime::OnReset)\n    //}}AFX_MSG_MAP\nEND_MESSAGE_MAP()\n\n/////////////////////////////////////////////////////////////////////////////\n// CEditTime message handlers\n\nvoid CEditTime::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) \n{\n    if (nChar >= 32)\n    {\n        int iStartIndex = -1;\n        int iEndIndex = -1;\n\n        GetSel(iStartIndex, iEndIndex);\n        CString strProposedText;\n        GetWindowText(strProposedText);\n        strProposedText.Delete(iStartIndex, iEndIndex - iStartIndex);\n        strProposedText.Insert(iStartIndex, static_cast<TCHAR>(nChar));\n\n        if (!Match(strProposedText))\n            return;\n    }\n    CEdit::OnChar(nChar, nRepCnt, nFlags);\n}\n\nvoid CEditTime::Reset()\n{\n    SendNotifyMessage(WM_RESET, 0, 0);\n}\n\nvoid CEditTime::SetValue(double fTime)\n{\n    SetWindowText(secondsToString(fTime * 1000, true).c_str());\n}\n\ndouble CEditTime::GetValue() const\n{\n\tCString strBuf;\n\tGetWindowText(strBuf);\n    return ParseTime(strBuf);\n}\n\nbool CEditTime::IsEmpty() const\n{\n    CString strBuf;\n    GetWindowText(strBuf);\n    return strBuf.IsEmpty();\n}\n\nLRESULT CEditTime::OnReset(WPARAM, LPARAM)\n{\n    SetWindowText(_T(\"\"));\n    return 0;\n}\n"
  },
  {
    "path": "Player/EditTime.h",
    "content": "#pragma once\n\n/////////////////////////////////////////////////////////////////////////////\n// CEditTime window\n\nclass CEditTime : public CEdit\n{\n// Construction\npublic:\n\tCEditTime();\n\n// Attributes\npublic:\n\tvoid Reset();\n\tvoid SetValue(double fTime);\n\tdouble GetValue() const;\n    bool IsEmpty() const;\n\n// Operations\n\n// Overrides\n\t// ClassWizard generated virtual function overrides\n\t//{{AFX_VIRTUAL(CEditTime)\n\t//}}AFX_VIRTUAL\n\n// Implementation\npublic:\n\tvirtual ~CEditTime();\n\n\t// Generated message map functions\nprotected:\n    //{{AFX_MSG(CEditTime)\n    afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);\n    afx_msg LRESULT OnReset(WPARAM wParam, LPARAM lParam);\n    //}}AFX_MSG\n\n    DECLARE_MESSAGE_MAP()\n\nprivate:\n\tCFont m_Font;\n};\n\n/////////////////////////////////////////////////////////////////////////////\n\n//{{AFX_INSERT_LOCATION}}\n// Microsoft Developer Studio will insert additional declarations immediately before the previous line.\n\n"
  },
  {
    "path": "Player/FrameToHglobal.cpp",
    "content": "#include \"stdafx.h\"\n#include \"FrameToHglobal.h\"\n\n#include \"ffmpeg_dxva2.h\"\n\nextern \"C\"\n{\n#include \"libavutil/frame.h\"\n#include \"libswscale/swscale.h\"\n};\n\nHGLOBAL FrameToHglobal(IDirect3DSurface9* surface, int width, int height, int allocatedHeight)\n{\n    AVFrame* tmp_frame = av_frame_alloc();\n\n    int res = dxva2_convert_data(surface, tmp_frame, width, allocatedHeight);\n    if (res != 0)\n    {\n        av_frame_free(&tmp_frame);\n        return NULL;\n    }\n\n    const int stride = ((width * 3) + 3) & ~3;\n\n    auto hMem = GlobalAlloc(GMEM_MOVEABLE, sizeof(BITMAPINFOHEADER) + stride * height);\n\n    if (hMem == NULL) {\n        av_frame_free(&tmp_frame);\n        return NULL;\n    }\n\n    auto bmi = static_cast<BITMAPINFOHEADER*>(GlobalLock(hMem));\n    if (!bmi) {\n        GlobalFree(hMem);\n        av_frame_free(&tmp_frame);\n        return NULL;\n    }\n\n    memset(bmi, 0, sizeof(BITMAPINFOHEADER));\n    bmi->biSize = sizeof(BITMAPINFOHEADER);\n    bmi->biWidth = width;\n    bmi->biHeight = -height;\n\n    bmi->biPlanes = 1;\n    bmi->biBitCount = 24; \n    bmi->biCompression = BI_RGB;\n\n    const auto pData = static_cast<uint8_t*>(static_cast<void*>(bmi + 1));\n\n    auto img_convert_ctx = sws_getContext(tmp_frame->width, tmp_frame->height, (AVPixelFormat)tmp_frame->format,\n        width, allocatedHeight, AV_PIX_FMT_BGR24, SWS_FAST_BILINEAR, NULL, NULL, NULL);\n\n    sws_scale(img_convert_ctx, tmp_frame->data, tmp_frame->linesize, 0, height,\n        &pData, &stride);\n\n    sws_freeContext(img_convert_ctx);\n\n    GlobalUnlock(hMem);\n    av_frame_free(&tmp_frame);\n\n    return hMem;\n}\n"
  },
  {
    "path": "Player/FrameToHglobal.h",
    "content": "#pragma once\n\nstruct IDirect3DSurface9;\n\nHGLOBAL FrameToHglobal(IDirect3DSurface9* surface, int width, int height, int allocatedHeight);\n"
  },
  {
    "path": "Player/FrameTransformer.cpp",
    "content": "#include \"stdafx.h\"\n\n#include \"FrameTransformer.h\"\n#include <stdexcept>\n#include <cstring>\n\nextern \"C\" {\n#include <libavutil/opt.h>\n#include <libavutil/imgutils.h>\n#include <libavutil/pixfmt.h>\n}\n\nconst auto PIX_FMT = AV_PIX_FMT_NV12;\n\nFrameTransformer::FrameTransformer(std::string filter_desc)\n  : filter_desc_(std::move(filter_desc)) {}\n\nint FrameTransformer::init(int in_w, int in_h, AVRational time_base){\n    time_base_ = time_base;\n    return create_graph(in_w, in_h, PIX_FMT);\n}\n\nint FrameTransformer::create_graph(int in_w, int in_h, AVPixelFormat in_pix_fmt){\n    if (initialized_) return 0;\n    int ret = 0;\n    char args[512];\n\n    {\n        auto graph = avfilter_graph_alloc();\n        if (!graph)\n            return AVERROR(ENOMEM);\n        graph_.reset(graph, [](AVFilterGraph* p) { avfilter_graph_free(&p); });\n    }\n\n    const AVFilter* buffersrc  = avfilter_get_by_name(\"buffer\");\n    const AVFilter* buffersink = avfilter_get_by_name(\"buffersink\");\n    if (!buffersrc || !buffersink) { ret = AVERROR_FILTER_NOT_FOUND; goto fail; }\n\n    snprintf(args, sizeof(args),\n             \"video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=1/1\",\n             in_w, in_h, in_pix_fmt, time_base_.num, time_base_.den);\n\n    ret = avfilter_graph_create_filter(&buffersrc_ctx_, buffersrc, \"in\", args, nullptr, graph_.get());\n    if (ret < 0) goto fail;\n\n    ret = avfilter_graph_create_filter(&buffersink_ctx_, buffersink, \"out\", nullptr, nullptr, graph_.get());\n    if (ret < 0) goto fail;\n\n    // Set buffersink to accept NV12 output\n    enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_NV12 };\n    ret = av_opt_set_bin(\n        buffersink_ctx_,\n        \"pix_fmts\",\n        (const uint8_t*)pix_fmts,\n        sizeof(pix_fmts),\n        AV_OPT_SEARCH_CHILDREN\n    );\n    if (ret < 0) goto fail;\n\n    // Parse and link the user filter chain between src and sink\n    AVFilterInOut* outputs = avfilter_inout_alloc();\n    AVFilterInOut* inputs  = avfilter_inout_alloc();\n    outputs->name       = av_strdup(\"in\");\n    outputs->filter_ctx = buffersrc_ctx_;\n    outputs->pad_idx    = 0;\n    outputs->next       = nullptr;\n\n    inputs->name        = av_strdup(\"out\");\n    inputs->filter_ctx  = buffersink_ctx_;\n    inputs->pad_idx     = 0;\n    inputs->next        = nullptr;\n\n    ret = avfilter_graph_parse_ptr(graph_.get(), filter_desc_.c_str(), &inputs, &outputs, nullptr);\n    avfilter_inout_free(&inputs);\n    avfilter_inout_free(&outputs);\n    if (ret < 0) goto fail;\n\n    ret = avfilter_graph_config(graph_.get(), nullptr);\n    if (ret < 0) goto fail;\n\n    w_ = in_w;\n    h_ = in_h;\n    initialized_ = true;\n    return 0;\n\nfail:\n    free_graph();\n    return ret;\n}\n\nbool FrameTransformer::operator()(OrderedScopedTokenGenerator::Token t, uint8_t* input, int in_stride, int in_w, int in_h, int64_t pts,\n                              std::vector<uint8_t>& output, int& out_w, int& out_h)\n{\n    if (w_ != in_w || h_ != in_h)\n        free_graph();\n\n    if (!initialized_) {\n        int r = init(in_w, in_h, time_base_); // assume input pixfmt; caller can init explicitly\n        if (r < 0)\n            return false;// r;\n    }\n\n    AVFrame* frame = av_frame_alloc();\n    frame->format = PIX_FMT; // adjust if needed\n    frame->width  = in_w;\n    frame->height = in_h;\n    frame->linesize[0] = in_stride;\n    frame->pts    = pts;\n    av_image_fill_arrays(frame->data, frame->linesize, input, (AVPixelFormat)frame->format, in_w, in_h, 1);\n    \n    AVFrame* filt = nullptr;\n    {\n        auto scope = t.lock(); // blocks until it's this token's generation order\n\n        int ret = av_buffersrc_add_frame_flags(buffersrc_ctx_, frame, AV_BUFFERSRC_FLAG_KEEP_REF);\n        av_frame_free(&frame);\n        if (ret < 0)\n            return false;// ret;\n\n        // pull filtered frames\n        filt = av_frame_alloc();\n        ret = av_buffersink_get_frame(buffersink_ctx_, filt);\n        if (ret < 0) {\n            av_frame_free(&filt);\n            return false;// ret;\n        }\n    }\n\n    // copy NV12 planar data into output vector\n    out_w = filt->width; out_h = filt->height;\n    int y_size = out_w * out_h;\n    int uv_size = out_w * ((out_h+1)/2);\n    output.resize(y_size + uv_size);\n    // Y plane\n    for (int i=0;i<out_h;i++)\n        memcpy(output.data() + i*out_w, filt->data[0] + i*filt->linesize[0], out_w);\n    // UV interleaved plane\n    for (int i=0;i<(out_h+1)/2;i++)\n        memcpy(output.data() + y_size + i*out_w, filt->data[1] + i*filt->linesize[1], out_w);\n\n    av_frame_free(&filt);\n    return true;// 0;\n}\n\nvoid FrameTransformer::free_graph()\n{\n    graph_.reset();\n    buffersrc_ctx_ = nullptr;\n    buffersink_ctx_ = nullptr;\n    initialized_ = false;\n    w_ = 0;\n    h_ = 0;\n}\n"
  },
  {
    "path": "Player/FrameTransformer.h",
    "content": "// FrameTransformer.h\n#pragma once\n\n#include \"ordered_scoped_token.h\"\n\nextern \"C\" {\n#include <libavutil/avutil.h>\n#include <libavutil/pixfmt.h>\n#include <libavutil/frame.h>\n#include <libavfilter/avfilter.h>\n#include <libavfilter/buffersrc.h>\n#include <libavfilter/buffersink.h>\n}\n#include <string>\n#include <vector>\n\n/*\nUsage:\n    FrameTransformer frameTransformer(\"crop=iw/2:ih:0:0,split[left][tmp];[tmp]hflip[right];[left][right] hstack\");\n    auto [width, height] = m_frameDecoder->getVideoSize();\n    frameTransformer.init(width, height);\n    m_frameDecoder->setImageConversionFunc(frameTransformer);\n*/\n\nclass FrameTransformer {\npublic:\n    FrameTransformer(std::string filter_desc);\n\n    // Initialize with input properties (called automatically on first process if not called)\n    int init(int in_w, int in_h, AVRational time_base = {1, 25});\n\n    // Process one frame. pts is optional (pass AV_NOPTS_VALUE if unknown).\n    // Returns success.\n    bool operator()(OrderedScopedTokenGenerator::Token t, \n                uint8_t* input, int in_stride, int in_w, int in_h, int64_t pts,\n                std::vector<uint8_t>& output, int& out_w, int& out_h);\n\n    void reset();\n\nprivate:\n    std::string filter_desc_;\n    std::shared_ptr<AVFilterGraph> graph_;\n    AVFilterContext* buffersrc_ctx_ = nullptr;\n    AVFilterContext* buffersink_ctx_ = nullptr;\n    bool initialized_ = false;\n    AVRational time_base_ = {1,25};\n    int w_ = 0;\n    int h_ = 0;\n\n    int create_graph(int in_w, int in_h, AVPixelFormat in_pix_fmt);\n    void free_graph();\n};\n"
  },
  {
    "path": "Player/GetClipboardText.h",
    "content": "#pragma once\n\n#include <string>\n\ninline std::string GetClipboardText()\n{\n    std::string text;\n\n    // Try opening the clipboard\n    if (OpenClipboard(nullptr))\n    {\n        // Get handle of clipboard object for ANSI text\n        if (HANDLE hData = GetClipboardData(CF_TEXT))\n        {\n            // Lock the handle to get the actual text pointer\n            if (const char* pszText = static_cast<const char*>(GlobalLock(hData)))\n            {\n                // Save text in a string class instance\n                text = pszText;\n            }\n            // Release the lock\n            GlobalUnlock(hData);\n        }\n\n        // Release the clipboard\n        CloseClipboard();\n    }\n\n    return text;\n}\n"
  },
  {
    "path": "Player/HandleFilesSequence.cpp",
    "content": "#include \"stdafx.h\"\n\n#include \"HandleFilesSequence.h\"\n\n#include <algorithm>\n#include <vector>\n\nnamespace {\n\nauto MakeComparableConsideringNumbers(const CString& s)\n{\n    std::vector<unsigned int> result;\n\n    unsigned int accum = 0;\n    for (int i = 0; i < s.GetLength(); ++i)\n    {\n        const auto c = s[i];\n        if ((c >= _T('0') && accum != 0 || c > _T('0')) && c <= _T('9'))\n        {\n            accum = accum * 10 + (c - _T('0'));\n        }\n        else\n        {\n            if (accum != 0)\n            {\n                result.push_back(accum + static_cast<unsigned int>(_T('0')));\n                accum = 0;\n            }\n            result.push_back((static_cast<unsigned>(c) < static_cast<unsigned>(_T('9'))) \n                ? c : (0xFFFF0000 | c));\n        }\n    }\n\n    if (accum != 0)\n    {\n        result.push_back(accum + static_cast<unsigned int>(_T('0')));\n    }\n\n    return result;\n}\n\nbool CompareConsideringNumbers(CString left, CString right)\n{\n    const auto leftConverted = MakeComparableConsideringNumbers(left.MakeUpper());\n    const auto rightConverted = MakeComparableConsideringNumbers(right.MakeUpper());\n\n    return std::lexicographical_compare(\n        rightConverted.begin(), rightConverted.end(), leftConverted.begin(), leftConverted.end());\n}\n\n}\n\nbool HandleFilesSequence(const CString& pathName,\n    bool looping,\n    std::function<bool(const CString&)> tryToOpen, \n    bool invert /*= false*/)\n{\n    const auto extension = PathFindExtension(pathName);\n    const auto fileName = PathFindFileName(pathName);\n    if (!extension || !fileName)\n        return false;\n    const CString directory(pathName, fileName - pathName);\n    const CString pattern((directory + _T('*')) + extension);\n\n    WIN32_FIND_DATA ffd{};\n    const auto hFind = FindFirstFile(pattern, &ffd);\n\n    if (INVALID_HANDLE_VALUE == hFind)\n    {\n        return false;\n    }\n\n    std::vector<CString> filesArr[2];\n    const auto extensionLength = pathName.GetLength() - (extension - pathName);\n    const CString justFileName(fileName, extension - fileName);\n\n    do\n    {\n        if (!(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\n        {\n            const auto length = _tcslen(ffd.cFileName);\n            if (length > extensionLength && ffd.cFileName[length - extensionLength] == _T('.'))\n            {\n                CString cFileName(ffd.cFileName, length - extensionLength);\n                const bool beforeOrEqual = !CompareConsideringNumbers(cFileName, justFileName);\n                filesArr[beforeOrEqual].push_back(cFileName);\n            }\n        }\n    } while (FindNextFile(hFind, &ffd));\n\n    FindClose(hFind);\n\n    for (int i = 0; i <= looping; ++i)\n    {\n        std::vector<CString>& files = filesArr[i ^ invert];\n        std::make_heap(files.begin(), files.end(), CompareConsideringNumbers);\n\n        while (!files.empty())\n        {\n            const CString path = directory + files.front() + extension;\n            if (tryToOpen(path))\n            {\n                return true;\n            }\n            std::pop_heap(files.begin(), files.end(), CompareConsideringNumbers);\n            files.pop_back();\n        }\n    }\n    return false;\n}\n"
  },
  {
    "path": "Player/HandleFilesSequence.h",
    "content": "#pragma once\n\n#include <functional>\n\nbool HandleFilesSequence(const CString& pathName,\n    bool looping,\n    std::function<bool(const CString&)> tryToOpen,\n    bool invert = false);\n"
  },
  {
    "path": "Player/I420Effect.cpp",
    "content": "#include \"stdafx.h\"\n#include <initguid.h>\n\n#include \"I420Effect.h\"\n\n#include \"I420Effect_PS.h\"\n\n\nI420Effect::I420Effect() :\nm_refCount(1)\n{\n    m_originalFrame = D2D1::SizeU(0, 0);\n}\n\nHRESULT I420Effect::Register(_In_ ID2D1Factory1* pFactory)\n{\n    // Format Effect metadata in XML as expected\n    PCWSTR pszXml =\n        LR\"(<?xml version='1.0' ?>\n        <Effect>\n        <!--System Properties-->\n        <Property name='DisplayName' type='string' value='I420' />\n        <Property name='Author' type='string' value='Public' />\n        <Property name='Category' type='string' value='CODEC' />\n        <Property name='Description' type='string' value='Adds a I420 Support' />\n        <Inputs>\n            <Input name='ySource' />\n            <Input name='uSource' />\n            <Input name='vSource' />\n        </Inputs>\n        </Effect>)\";\n\n    // Register the effect in the factory\n    return pFactory->RegisterEffectFromString(\n        CLSID_CustomI420Effect,\n        pszXml,\n        nullptr,\n        0,\n        CreateRippleImpl\n        );\n}\n\nHRESULT __stdcall I420Effect::CreateRippleImpl(_Outptr_ IUnknown** ppEffectImpl)\n{\n    // Since the object's refcount is initialized to 1, we don't need to AddRef here.\n    *ppEffectImpl = static_cast<ID2D1EffectImpl*>(new (std::nothrow) I420Effect());\n\n    if (*ppEffectImpl == nullptr)\n        return E_OUTOFMEMORY;\n    return S_OK;\n}\n\n\nIFACEMETHODIMP I420Effect::Initialize(\n    _In_ ID2D1EffectContext* pEffectContext,\n    _In_ ID2D1TransformGraph* pTransformGraph\n    )\n{\n    HRESULT hr = pEffectContext->LoadPixelShader(GUID_I420PixelShader, I420Effect_ByteCode, ARRAYSIZE(I420Effect_ByteCode));\n    if (SUCCEEDED(hr))\n    {\n        // This loads the shader into the Direct2D image effects system and associates it with the GUID passed in.\n        // If this method is called more than once (say by other instances of the effect) with the same GUID,\n        // the system will simply do nothing, ensuring that only one instance of a shader is stored regardless of how\n        // many time it is used.\n\n        // The graph consists of a single transform. In fact, this class is the transform,\n        // reducing the complexity of implementing an effect when all we need to\n        // do is use a single pixel shader.\n        hr = pTransformGraph->SetSingleTransformNode(this);\n    }\n\n    return S_OK;\n}\n\nIFACEMETHODIMP I420Effect::PrepareForRender(D2D1_CHANGE_TYPE /*changeType*/)\n{\n    return S_OK;\n}\n\n// SetGraph is only called when the number of inputs changes. This never happens as we publish this effect\n// as a single input effect.\nIFACEMETHODIMP I420Effect::SetGraph(_In_ ID2D1TransformGraph* /*pGraph*/)\n{\n    return E_NOTIMPL;\n}\n\n// Called to assign a new render info class, which is used to inform D2D on\n// how to set the state of the GPU.\nIFACEMETHODIMP I420Effect::SetDrawInfo(_In_ ID2D1DrawInfo* pDrawInfo)\n{\n    HRESULT hr = S_OK;\n\n    m_drawInfo = pDrawInfo;\n\n    hr = m_drawInfo->SetPixelShader(GUID_I420PixelShader);\n\n    if (SUCCEEDED(hr))\n    {\n        // Providing this hint allows D2D to optimize performance when processing large images.\n        m_drawInfo->SetInstructionCountHint(sizeof(I420Effect_ByteCode));\n    }\n\n    return hr;\n}\n\n// Calculates the mapping between the output and input rects. In this case,\n// we want to request an expanded region to account for pixels that the ripple\n// may need outside of the bounds of the destination.\nIFACEMETHODIMP I420Effect::MapOutputRectToInputRects(\n    _In_ const D2D1_RECT_L* /*pOutputRect*/,\n    _Out_writes_(inputRectCount) D2D1_RECT_L* pInputRects,\n    UINT32 inputRectCount\n    ) const\n{\n    if (inputRectCount != 3)\n        return E_NOTIMPL;\n\n    pInputRects[0] = m_inputRect;\n    pInputRects[1] = pInputRects[2] = { m_inputRect.left / 2, m_inputRect.top / 2, m_inputRect.right / 2, m_inputRect.bottom / 2 };\n\n    return S_OK;\n}\n\nIFACEMETHODIMP I420Effect::MapInputRectsToOutputRect(\n    _In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputRects,\n    _In_reads_(inputRectCount) CONST D2D1_RECT_L* /*pInputOpaqueSubRects*/,\n    UINT32 /*inputRectCount*/,\n    _Out_ D2D1_RECT_L* pOutputRect,\n    _Out_ D2D1_RECT_L* pOutputOpaqueSubRect\n    )\n{\n    *pOutputRect = pInputRects[0];\n\n    if (m_inputRect.bottom != pInputRects[0].bottom\n        || m_inputRect.top != pInputRects[0].top\n        || m_inputRect.right != pInputRects[0].right\n        || m_inputRect.left != pInputRects[0].left)\n    {\n        m_inputRect = pInputRects[0];\n        m_originalFrame.width = m_inputRect.right;\n        m_originalFrame.height = m_inputRect.bottom;\n    }\n\n    // Indicate that entire output might contain transparency.\n    ZeroMemory(pOutputOpaqueSubRect, sizeof(*pOutputOpaqueSubRect));\n\n    return S_OK;\n}\n\nIFACEMETHODIMP I420Effect::MapInvalidRect(\n    UINT32 /*inputIndex*/,\n    D2D1_RECT_L /*invalidInputRect*/,\n    _Out_ D2D1_RECT_L* pInvalidOutputRect\n    ) const\n{\n    HRESULT hr = S_OK;\n\n    // Indicate that the entire output may be invalid.\n    *pInvalidOutputRect = m_inputRect;\n\n    return hr;\n}\n\nIFACEMETHODIMP_(UINT32) I420Effect::GetInputCount() const\n{\n    return 3;\n}\n\n// D2D ensures that that effects are only referenced from one thread at a time.\n// To improve performance, we simply increment/decrement our reference count\n// rather than use atomic InterlockedIncrement()/InterlockedDecrement() functions.\nIFACEMETHODIMP_(ULONG) I420Effect::AddRef()\n{\n    ++m_refCount;\n    return m_refCount;\n}\n\nIFACEMETHODIMP_(ULONG) I420Effect::Release()\n{\n    --m_refCount;\n\n    if (m_refCount == 0)\n    {\n        delete this;\n        return 0;\n    }\n    else\n    {\n        return m_refCount;\n    }\n}\n\n// This enables the stack of parent interfaces to be queried. In the instance\n// of the Ripple interface, this method simply enables the developer\n// to cast a Ripple instance to an ID2D1EffectImpl or IUnknown instance.\nIFACEMETHODIMP I420Effect::QueryInterface(_In_ REFIID riid, _Outptr_ void** ppOutput)\n{\n    static const QITAB rgqit[] =\n    {\n        QITABENT(I420Effect, ID2D1EffectImpl),\n        QITABENT(I420Effect, ID2D1DrawTransform),\n        QITABENT(I420Effect, ID2D1Transform),\n        QITABENT(I420Effect, ID2D1TransformNode),\n        { 0 },\n    };\n\n    return QISearch(this, rgqit, riid, ppOutput);\n}\n"
  },
  {
    "path": "Player/I420Effect.h",
    "content": "#pragma once\n\n#include <d2d1effectauthor.h>\n\n// {3AB41678-D4BC-4BE1-8A91-07A63DEEFEA1}\nDEFINE_GUID(GUID_I420PixelShader, 0x3ab41678, 0xd4bc, 0x4be1, 0x8a, 0x91, 0x7, 0xa6, 0x3d, 0xee, 0xfe, 0xa1);\n// {DA637E40-44D4-4617-A3D3-A28344549EEA}\nDEFINE_GUID(CLSID_CustomI420Effect, 0xda637e40, 0x44d4, 0x4617, 0xa3, 0xd3, 0xa2, 0x83, 0x44, 0x54, 0x9e, 0xea);\n\nclass I420Effect : public ID2D1EffectImpl, public ID2D1DrawTransform\n{\npublic:\n    // Declare effect registration methods.\n    static HRESULT Register(_In_ ID2D1Factory1* pFactory);\n    static HRESULT __stdcall CreateRippleImpl(_Outptr_ IUnknown** ppEffectImpl);\n\n    // Declare ID2D1EffectImpl implementation methods.\n    IFACEMETHODIMP Initialize(_In_ ID2D1EffectContext* pContextInternal, _In_ ID2D1TransformGraph* pTransformGraph);\n    IFACEMETHODIMP PrepareForRender(D2D1_CHANGE_TYPE changeType);\n    IFACEMETHODIMP SetGraph(_In_ ID2D1TransformGraph* pGraph);\n\n    // Declare ID2D1DrawTransform implementation methods.\n    IFACEMETHODIMP SetDrawInfo(_In_ ID2D1DrawInfo* pRenderInfo);\n\n    // Declare ID2D1Transform implementation methods.\n    IFACEMETHODIMP MapOutputRectToInputRects(\n        _In_ const D2D1_RECT_L* pOutputRect,\n        _Out_writes_(inputRectCount) D2D1_RECT_L* pInputRects,\n        UINT32 inputRectCount\n        ) const;\n\n    IFACEMETHODIMP MapInputRectsToOutputRect(\n        _In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputRects,\n        _In_reads_(inputRectCount) CONST D2D1_RECT_L* pInputOpaqueSubRects,\n        UINT32 inputRectCount,\n        _Out_ D2D1_RECT_L* pOutputRect,\n        _Out_ D2D1_RECT_L* pOutputOpaqueSubRect\n        );\n\n    IFACEMETHODIMP MapInvalidRect(\n        UINT32 inputIndex,\n        D2D1_RECT_L invalidInputRect,\n        _Out_ D2D1_RECT_L* pInvalidOutputRect\n        ) const;\n\n    // Declare ID2D1TransformNode implementation methods.\n    IFACEMETHODIMP_(UINT32) GetInputCount() const;\n\n    // Declare IUnknown implementation methods.\n    IFACEMETHODIMP_(ULONG) AddRef();\n    IFACEMETHODIMP_(ULONG) Release();\n    IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _Outptr_ void** ppOutput);\nprivate:\n\n    I420Effect();\n\n    CComPtr<ID2D1DrawInfo>      m_drawInfo;\n\n    LONG                        m_refCount;\n    D2D1_RECT_L                 m_inputRect;\n    D2D1_SIZE_U                 m_originalFrame;\n};\n"
  },
  {
    "path": "Player/I420Effect_PS.hlsl",
    "content": "Texture2D yTexture : register(t0);\nTexture2D uTexture : register(t1);\nTexture2D vTexture : register(t2);\n\nSamplerState ySampler : register(s0);\nSamplerState uSampler : register(s1);\nSamplerState vSampler : register(s2);\n\nfloat4 main(\n\tfloat4 pos      : SV_POSITION,\n\tfloat4 posScene : SCENE_POSITION,\n\tfloat4 uv0 : TEXCOORD0\n\t) : SV_Target\n{\n\tfloat Y = yTexture.Sample(ySampler, uv0).a * 255;\n\tfloat U = uTexture.Sample(uSampler, uv0).a * 255;\n\tfloat V = vTexture.Sample(vSampler, uv0).a * 255;\n\n\tfloat4 color = float4(0, 0, 0, 1.0f);\n\n\tcolor.b = clamp(1.164383561643836*(Y - 16) + 2.017232142857142*(U - 128), 0, 255) / 255.0f;\n\tcolor.g = clamp(1.164383561643836*(Y - 16) - 0.812967647237771*(V - 128) - 0.391762290094914*(U - 128), 0, 255) / 255.0f;\n\tcolor.r = clamp(1.164383561643836*(Y - 16) + 1.596026785714286*(V - 128), 0, 255) / 255.0f;\n\n\treturn color;\n}"
  },
  {
    "path": "Player/IEraseableArea.h",
    "content": "#pragma once\n\nclass CWnd;\nclass CDC;\n\nclass IEraseableArea\n{\npublic:\n    virtual void OnErase(CWnd* pInitiator, CDC* pDC, BOOL isFullScreen) = 0;\n};\n"
  },
  {
    "path": "Player/ImageUpscale.cpp",
    "content": "#include \"stdafx.h\"\n\n#include \"ImageUpscale.h\"\n\n#if __has_include(\"AC.hpp\")\n\n#include\"AC.hpp\"\n#include\"ACCreator.hpp\"\n#include\"ACProcessor.hpp\"\n#include \"Anime4KCPP.hpp\"\n\n\nconst int currPlatformID = 0;\nconst int currDeviceID = 0;\n\nbool CanUpscaleImage()\n{\n    static const bool ok = LoadLibrary(_T(\"opencl.dll\")) != NULL\n        && Anime4KCPP::OpenCL::checkGPUSupport(currPlatformID, currDeviceID);\n    return ok;\n}\n\nbool EnableImageUpscale()\n{\n    static Anime4KCPP::ACInitializer initializer;\n\n    static const auto ok = [] {\n        const int OpenCLQueueNum = 1;\n        const bool OpenCLParallelIO = false;\n\n        initializer.pushManager<Anime4KCPP::OpenCL::Manager<Anime4KCPP::OpenCL::ACNet>>(\n            currPlatformID, currDeviceID,\n            Anime4KCPP::CNNType::Default,\n            OpenCLQueueNum,\n            OpenCLParallelIO);\n\n        return initializer.init() == initializer.size();\n    }();\n    return ok;\n}\n\nbool ImageUpscale(OrderedScopedTokenGenerator::Token, uint8_t* input, int inputStride, int inputWidth, int inputHeight,\n    int64_t, std::vector<uint8_t>& output, int& outputWidth, int& outputHeight)\n{\n    Anime4KCPP::Parameters param{};\n    auto ac = Anime4KCPP::ACCreator::createUP(param, Anime4KCPP::Processor::Type::OpenCL_ACNet);\n\n    const cv::Mat y_image(inputHeight, inputWidth, CV_8UC1, input, inputStride);\n    const cv::Mat uv_image(inputHeight / 2, inputWidth / 2, CV_8UC2, input + inputHeight * inputStride, inputStride);\n    cv::Mat cbcr_channels[2];\n    split(uv_image, cbcr_channels);\n\n    ac->loadImage(y_image, cbcr_channels[0], cbcr_channels[1]);\n\n    ac->process();\n\n    cv::Mat out_y_image;\n    std::vector <cv::Mat> out_cbcr_channels(2);\n\n    ac->saveImage(out_y_image, out_cbcr_channels[0], out_cbcr_channels[1]);\n\n    outputWidth = out_y_image.cols;\n    outputHeight = out_y_image.rows;\n\n    cv::Mat CrCb;\n    merge(out_cbcr_channels, CrCb);\n\n    output.assign(out_y_image.datastart, out_y_image.dataend);\n    output.insert(output.end(), CrCb.datastart, CrCb.dataend);\n\n    return true;\n}\n\n#else\n\nbool CanUpscaleImage()\n{\n    return false;\n}\n\nbool EnableImageUpscale()\n{\n    return false;\n}\n\nbool ImageUpscale(OrderedScopedTokenGenerator::Token, uint8_t*, int, int, int, int64_t, std::vector<uint8_t>&, int&, int&)\n{\n}\n\n#endif\n"
  },
  {
    "path": "Player/ImageUpscale.h",
    "content": "#pragma once\n\n#include \"ordered_scoped_token.h\"\n\n#include <cstdint>\n#include <vector>\n\nbool CanUpscaleImage();\n\nbool EnableImageUpscale();\n\nbool ImageUpscale(OrderedScopedTokenGenerator::Token, uint8_t* input, int inputStride, int inputWidth, int inputHeight,\n    int64_t, std::vector<uint8_t>& output, int& outputWidth, int& outputHeight);\n"
  },
  {
    "path": "Player/MainFrm.cpp",
    "content": "\n// MainFrm.cpp : implementation of the CMainFrame class\n//\n\n#include \"stdafx.h\"\n#include \"Player.h\"\n\n#include \"MainFrm.h\"\n#include \"PlayerDoc.h\"\n#include \"IEraseableArea.h\"\n#include \"MakeDelegate.h\"\n\n#ifdef _DEBUG\n#define new DEBUG_NEW\n#endif\n\nnamespace {\n\nHICON LoadIcon(int idr)\n{\n    int const cxButton = GetSystemMetrics(SM_CXSMICON);\n    return (HICON) LoadImage(\n        AfxGetApp()->m_hInstance,\n        MAKEINTRESOURCE(idr),\n        IMAGE_ICON,\n        cxButton, cxButton, // use actual size\n        LR_DEFAULTCOLOR);\n}\n\n\nclass FullScreenBarAccessor : public CFullScreenImpl\n{\npublic:\n    CMFCToolBar* GetFullScreenBar() { return m_pwndFullScreenBar; }\n};\n\nclass FullScreenMgrAccessor : public CFrameImpl\n{\npublic:\n    CMFCToolBar* GetFullScreenBar() \n    { \n        return static_cast<FullScreenBarAccessor&>(m_FullScreenMgr).GetFullScreenBar(); \n    }\n};\n\nclass DocumentAccessor : public CView\n{\npublic:\n    CPlayerDoc* GetDocument()\n    {\n        return dynamic_cast<CPlayerDoc*>(m_pDocument);\n    }\n};\n\nUINT s_uTBBC = RegisterWindowMessage(L\"TaskbarButtonCreated\");\n\n} // namespace\n\n// CMainFrame\n\nIMPLEMENT_DYNCREATE(CMainFrame, CFrameWndEx)\n\nBEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)\n    ON_WM_CREATE()\n    ON_WM_CLOSE()\n    ON_COMMAND(IDC_FULL_SCREEN, &CMainFrame::OnFullScreen)\n    ON_WM_ERASEBKGND()\n    ON_WM_WINDOWPOSCHANGED()\n    ON_WM_NCPAINT()\n    ON_WM_POWERBROADCAST()\n    ON_REGISTERED_MESSAGE(s_uTBBC, &CMainFrame::CreateThumbnailToolbar)\n    ON_WM_NCHITTEST()\n    ON_WM_INITMENUPOPUP()\nEND_MESSAGE_MAP()\n\nstatic UINT indicators[] =\n{\n    ID_SEPARATOR,           // status line indicator\n    ID_INDICATOR_CAPS,\n    ID_INDICATOR_NUM,\n    ID_INDICATOR_SCRL,\n};\n\n// CMainFrame construction/destruction\n\nCMainFrame::CMainFrame()\n    : m_bFullScreen(FALSE)\n{\n    // TODO: add member initialization code here\n}\n\nCMainFrame::~CMainFrame()\n{\n}\n\nBOOL CMainFrame::Create(LPCTSTR lpszClassName,\n    LPCTSTR lpszWindowName,\n    DWORD dwStyle,\n    const RECT& rect,\n    CWnd* pParentWnd,        // != NULL for popups\n    LPCTSTR lpszMenuName,\n    DWORD dwExStyle,\n    CCreateContext* pContext)\n{\n    const BOOL result = __super::Create(lpszClassName,\n        lpszWindowName,\n        dwStyle,\n        rect,\n        pParentWnd,        // != NULL for popups\n        lpszMenuName,\n        dwExStyle,\n        pContext);\n\n    if (result)\n    {\n        ASSERT(pContext->m_pCurrentDoc);\n        ASSERT(pContext->m_pCurrentDoc->IsKindOf(RUNTIME_CLASS(CPlayerDoc)));\n        m_wndPlayerControl.setDocument(static_cast<CPlayerDoc*>(pContext->m_pCurrentDoc));\n        m_wndRange.setDocument(static_cast<CPlayerDoc*>(pContext->m_pCurrentDoc));\n        static_cast<CPlayerDoc*>(pContext->m_pCurrentDoc)->onPauseResume.connect(\n            MAKE_DELEGATE(&CMainFrame::onPauseResume, this));\n    }\n\n    return result;\n}\n\nvoid CMainFrame::pauseResume()\n{\n    if (CView* pView = dynamic_cast<CView*>(GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE)))\n    {\n        if (CPlayerDoc* pDoc = static_cast<DocumentAccessor*>(pView)->GetDocument())\n        {\n            if (pDoc->isPlaying())\n                pDoc->pauseResume();\n        }\n    }\n}\n\nBOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)\n{\n    if (LOWORD(wParam) == IDC_PLAY_PAUSE)\n    {\n        pauseResume();\n        return TRUE;\n    }\n    return __super::OnCommand(wParam, lParam);\n}\n\nBOOL CMainFrame::PreTranslateMessage(MSG* pMsg)\n{\n    if (pMsg->message == WM_KEYDOWN\n        && GetKeyState(VK_SHIFT) >= 0 && GetKeyState(VK_CONTROL) >= 0 && GetKeyState(VK_MENU) >= 0)\n    {\n        switch (pMsg->wParam)\n        {\n        case VK_SPACE:\n            pauseResume();\n            return TRUE;\n        case VK_F11:\n            if (IsFullScreen())\n                ShowFullScreen();\n            else\n                OnFullScreen();\n            return TRUE;\n        }\n    }\n    return __super::PreTranslateMessage(pMsg);\n}\n\n\nint CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)\n{\n    if (__super::OnCreate(lpCreateStruct) == -1)\n        return -1;\n\n    CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows7));\n    //CMFCVisualManagerOffice2007::SetStyle(CMFCVisualManagerWindows7::Office2007_ObsidianBlack);\n\n    if (!m_wndMenuBar.Create(this))\n    {\n        TRACE0(\"Failed to create menubar\\n\");\n        return -1;      // fail to create\n    }\n    m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);\n\n    //if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||\n    //\t!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))\n    //{\n    //\tTRACE0(\"Failed to create toolbar\\n\");\n    //\treturn -1;      // fail to create\n    //}\n\n    //if (!m_wndStatusBar.Create(this))\n    //{\n    //    TRACE0(\"Failed to create status bar\\n\");\n    //    return -1;      // fail to create\n    //}\n    //m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));\n\n    if (!m_wndPlayerControl.Create(\n        this, \n        IDD_DIALOGBAR_PLAYER_CONTROL, \n        WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_LEFT | CBRS_FLOAT_MULTI,\n        IDD_DIALOGBAR_PLAYER_CONTROL))\n    {\n        TRACE0(\"Failed to create player control dialog bar\\n\");\n        return -1;      // fail to create\n    }\n\n    if (!m_wndRange.Create(\n        this,\n        IDD_DIALOGBAR_RANGE,\n        WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | CBRS_LEFT | CBRS_FLOAT_MULTI,\n        IDD_DIALOGBAR_RANGE))\n    {\n        TRACE0(\"Failed to create range dialog bar\\n\");\n        return -1;      // fail to create\n    }\n\n    // TODO: Delete these three lines if you don't want the toolbar to be dockable\n    m_wndMenuBar.EnableDocking(CBRS_ALIGN_ANY);\n    //m_wndToolBar.EnableDocking(CBRS_ALIGN_TOP);\n    m_wndPlayerControl.EnableDocking(CBRS_ALIGN_BOTTOM);\n    m_wndRange.EnableDocking(CBRS_ALIGN_BOTTOM);\n\n    CString strBuffer;\n    VERIFY(strBuffer.LoadString(IDS_PLAYER_CONTROL));\n    m_wndPlayerControl.SetWindowText(strBuffer);\n\n    VERIFY(strBuffer.LoadString(IDS_RANGE));\n    m_wndRange.SetWindowText(strBuffer);\n\n    EnableDocking(CBRS_ALIGN_TOP | CBRS_ALIGN_BOTTOM);\n    DockPane(&m_wndMenuBar);\n    //DockPane(&m_wndToolBar, AFX_IDW_DOCKBAR_TOP);\n    DockPane(&m_wndPlayerControl, AFX_IDW_DOCKBAR_BOTTOM);\n    DockPane(&m_wndRange, AFX_IDW_DOCKBAR_BOTTOM);\n\n    // Enable toolbar and docking window menu replacement\n    VERIFY(strBuffer.LoadString(IDS_TOOLBAR_CUSTOMIZE));\n    //m_wndToolBar.EnableCustomizeButton(TRUE, ID_VIEW_CUSTOMIZE, strCustomize);\n    EnablePaneMenu(TRUE, ID_VIEW_CUSTOMIZE, strBuffer, ID_VIEW_TOOLBAR);\n\n    m_hPlay = LoadIcon(IDI_PLAY);\n    m_hPause = LoadIcon(IDI_PAUSE);\n\n    // In case the application is run elevated, allow the\n    // TaskbarButtonCreated and WM_COMMAND messages through.\n    ChangeWindowMessageFilter(s_uTBBC, MSGFLT_ADD);\n    ChangeWindowMessageFilter(WM_COMMAND, MSGFLT_ADD);\n\n    EnableFullScreenMode(IDC_FULL_SCREEN);\n    EnableFullScreenMainMenu(FALSE);\n\n    return 0;\n}\n\nvoid CMainFrame::OnClose()\n{\n    m_pTaskbarList.Release();\n    __super::OnClose();\n}\n\nLRESULT CMainFrame::CreateThumbnailToolbar(WPARAM, LPARAM)\n{\n    HRESULT hr = CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pTaskbarList));\n    if (SUCCEEDED(hr))\n    {\n        hr = m_pTaskbarList->HrInit();\n        if (SUCCEEDED(hr))\n        {\n            enum { NUM_ICONS = 1 };\n            int const cxButton = GetSystemMetrics(SM_CXSMICON);\n            if (auto himl = ImageList_Create(cxButton, cxButton, ILC_MASK, NUM_ICONS, 0))\n            {\n                hr = m_pTaskbarList->ThumbBarSetImageList(*this, himl);\n                if (SUCCEEDED(hr))\n                {\n                    THUMBBUTTON buttons[NUM_ICONS] = {};\n\n                    // First button\n                    buttons[0].dwMask = THB_ICON | THB_TOOLTIP | THB_FLAGS;\n                    buttons[0].dwFlags = THBF_ENABLED | THBF_DISMISSONCLICK;\n                    buttons[0].iId = IDC_PLAY_PAUSE;\n                    buttons[0].hIcon = m_hPause;\n                    CStringW strBuffer;\n                    VERIFY(strBuffer.LoadString(IDS_PAUSE));\n                    wcscpy_s(buttons[0].szTip, strBuffer);\n\n                    // Set the buttons to be the thumbnail toolbar\n                    hr = m_pTaskbarList->ThumbBarAddButtons(*this, ARRAYSIZE(buttons), buttons);\n                }\n                ImageList_Destroy(himl);\n            }\n        }\n    }\n\n    return TRUE;\n}\n\nvoid CMainFrame::onPauseResume(bool paused)\n{\n    if (m_pTaskbarList)\n    {\n        THUMBBUTTON buttons[1] = {};\n\n        // First button\n        buttons[0].dwMask = THB_ICON | THB_TOOLTIP | THB_FLAGS;\n        buttons[0].dwFlags = THBF_ENABLED | THBF_DISMISSONCLICK;\n        buttons[0].iId = IDC_PLAY_PAUSE;\n        buttons[0].hIcon = paused? m_hPlay : m_hPause;\n        CStringW strBuffer;\n        VERIFY(strBuffer.LoadString(paused? IDS_PLAY : IDS_PAUSE));\n        wcscpy_s(buttons[0].szTip, strBuffer);\n        m_pTaskbarList->ThumbBarUpdateButtons(*this, 1, buttons);\n    }\n}\n\nBOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)\n{\n    if( !__super::PreCreateWindow(cs) )\n        return FALSE;\n    // TODO: Modify the Window class or styles here by modifying\n    //  the CREATESTRUCT cs\n\n    return TRUE;\n}\n\n// CMainFrame diagnostics\n\n#ifdef _DEBUG\nvoid CMainFrame::AssertValid() const\n{\n    __super::AssertValid();\n}\n\nvoid CMainFrame::Dump(CDumpContext& dc) const\n{\n    __super::Dump(dc);\n}\n#endif //_DEBUG\n\n\n// CMainFrame message handlers\n\nvoid CMainFrame::OnFullScreen()\n{\n    ModifyStyle(WS_OVERLAPPEDWINDOW, 0, SWP_FRAMECHANGED);\n    const bool semiTransparentMode\n        = GetKeyState(VK_SHIFT) < 0 && GetKeyState(VK_CONTROL) < 0;\n    if (semiTransparentMode)\n    {\n        SetWindowPos(&wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);\n        ModifyStyleEx(0, WS_EX_LAYERED | WS_EX_TRANSPARENT);\n        SetLayeredWindowAttributes(0, (255 * 40) / 100, LWA_ALPHA);\n    }\n    ShowFullScreen();\n    if (CMFCToolBar* toolBar = static_cast<FullScreenMgrAccessor&>(m_Impl).GetFullScreenBar())\n    {\n        if (auto pFrame = toolBar->GetParentMiniFrame())\n        {\n            if (semiTransparentMode)\n            {\n                m_dockManager.RemoveMiniFrame(pFrame);\n            }\n            else\n            {\n                pFrame->ShowWindow(SW_HIDE);\n            }\n        }\n    }\n}\n\n\nBOOL CMainFrame::OnEraseBkgnd(CDC* pDC)\n{\n    CWnd* pWnd = GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE);\n    if (IEraseableArea* pEraseableArea = dynamic_cast<IEraseableArea*>(pWnd))\n    {\n        pEraseableArea->OnErase(this, pDC, IsFullScreen());\n    }\n\n    return TRUE;\n}\n\n\nvoid CMainFrame::OnWindowPosChanged(WINDOWPOS* lpwndpos)\n{\n    CFrameWndEx::OnWindowPosChanged(lpwndpos);\n\n    // message handler code here\n    if (!IsFullScreen() && m_bFullScreen)\n    {\n        ModifyStyle(0, WS_OVERLAPPEDWINDOW, 0);\n        // clear semi transparent settings\n        SetWindowPos(&wndNoTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);\n        ModifyStyleEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, 0);\n    }\n    m_bFullScreen = IsFullScreen();\n}\n\n\nvoid CMainFrame::OnNcPaint()\n{\n    if (!IsFullScreen())\n        Default();\n}\n\n\nUINT CMainFrame::OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData)\n{\n    if (nPowerEvent == PBT_APMSUSPEND)\n    {\n        if (CView* pView = dynamic_cast<CView*>(GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE)))\n        {\n            if (CPlayerDoc* pDoc = static_cast<DocumentAccessor*>(pView)->GetDocument())\n            {\n                if (pDoc->isPlaying() && !pDoc->isPaused())\n                    pDoc->pauseResume();\n                ShowWindow(SW_MINIMIZE);\n            }\n        }\n    }\n    return CFrameWndEx::OnPowerBroadcast(nPowerEvent, nEventData);\n}\n\nLRESULT CMainFrame::OnNcHitTest(CPoint point)\n{\n    enum { SPOT_SIZE = 8 };\n    CRect rect;\n    GetClientRect(rect);\n    rect.left = rect.right - SPOT_SIZE;\n    rect.top = rect.bottom - SPOT_SIZE;\n    rect.right += SPOT_SIZE;\n    rect.bottom += SPOT_SIZE;\n    ClientToScreen(&rect);\n\n    if (rect.PtInRect(point))\n    {\n        BOOL bRTL = GetExStyle() & WS_EX_LAYOUTRTL;\n        return bRTL ? HTBOTTOMLEFT : HTBOTTOMRIGHT;\n    }\n\n    return __super::OnNcHitTest(point);\n}\n\n\nvoid CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu)\n{\n    CFrameWndEx::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);\n\n    if (bSysMenu || pPopupMenu->GetMenuItemCount() != 1)\n        return;\n\n    if (CView* pView = dynamic_cast<CView*>(GetDescendantWindow(AFX_IDW_PANE_FIRST, TRUE)))\n    {\n        if (CPlayerDoc* pDoc = static_cast<DocumentAccessor*>(pView)->GetDocument())\n        {\n            switch (pPopupMenu->GetMenuItemID(0))\n            {\n            case ID_FIRST_SUBTITLE_DUMMY:\n                {\n                    pPopupMenu->DeleteMenu(0, MF_BYPOSITION);\n                    int id = ID_FIRST_SUBTITLE;\n                    for (auto& item : pDoc->getFrameDecoder()->listSubtitles())\n                    {\n                        pPopupMenu->AppendMenu(MF_STRING, id++, CA2T(item.c_str(), CP_UTF8));\n                    }\n                }\n                break;\n            case ID_TRACK1_DUMMY:\n                {\n                    pPopupMenu->DeleteMenu(0, MF_BYPOSITION);\n                    int id = ID_TRACK1;\n                    const int nTracks = pDoc->getFrameDecoder()->getNumAudioTracks();\n                    for (int i = 1; i <= nTracks; ++i)\n                    {\n                        CString name;\n                        name.Format(_T(\"Track %d\"), i);\n                        pPopupMenu->AppendMenu(MF_STRING, id++, name);\n                    }\n                }\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Player/MainFrm.h",
    "content": "\n// MainFrm.h : interface of the CMainFrame class\n//\n\n#pragma once\n\n#include \"DialogBarPlayerControl.h\"\n#include \"DialogBarRange.h\"\n\nstruct ITaskbarList3;\n\nclass CMainFrame : public CFrameWndEx\n{\n    \nprotected: // create from serialization only\n    CMainFrame();\n    DECLARE_DYNCREATE(CMainFrame)\n\n// Attributes\npublic:\n\n// Operations\nprivate:\n    void pauseResume();\n    void onPauseResume(bool paused);\n\n\n// Overrides\npublic:\n    BOOL OnCommand(WPARAM wParam, LPARAM lParam) override;\n    BOOL PreCreateWindow(CREATESTRUCT& cs) override;\n\n    BOOL Create(LPCTSTR lpszClassName,\n        LPCTSTR lpszWindowName,\n        DWORD dwStyle = WS_OVERLAPPEDWINDOW,\n        const RECT& rect = rectDefault,\n        CWnd* pParentWnd = NULL,        // != NULL for popups\n        LPCTSTR lpszMenuName = NULL,\n        DWORD dwExStyle = 0,\n        CCreateContext* pContext = NULL) override;\n\n    BOOL PreTranslateMessage(MSG* pMsg) override;\n\n\n// Implementation\npublic:\n    virtual ~CMainFrame();\n#ifdef _DEBUG\n    virtual void AssertValid() const;\n    virtual void Dump(CDumpContext& dc) const;\n#endif\n\nprotected:  // control bar embedded members\n    CMFCMenuBar       m_wndMenuBar;\n    //CMFCToolBar          m_wndToolBar;\n    //CMFCStatusBar        m_wndStatusBar;\n    CDialogBarPlayerControl m_wndPlayerControl;\n    CDialogBarRange m_wndRange;\n\n    BOOL            m_bFullScreen;\n\n    CComPtr<ITaskbarList3>  m_pTaskbarList;\n\n    HICON m_hPlay;\n    HICON m_hPause;\n\n// Generated message map functions\nprotected:\n    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);\n    afx_msg void OnClose();\n    afx_msg LRESULT CreateThumbnailToolbar(WPARAM wParam, LPARAM lParam);\n    afx_msg void OnFullScreen();\n    afx_msg BOOL OnEraseBkgnd(CDC* pDC);\n    afx_msg void OnWindowPosChanged(WINDOWPOS* lpwndpos);\n    afx_msg void OnNcPaint();\n    afx_msg UINT OnPowerBroadcast(UINT nPowerEvent, LPARAM nEventData);\n    afx_msg LRESULT OnNcHitTest(CPoint point);\n    DECLARE_MESSAGE_MAP()\npublic:\n    afx_msg void OnInitMenuPopup(CMenu* pPopupMenu, UINT nIndex, BOOL bSysMenu);\n};\n"
  },
  {
    "path": "Player/MakeDelegate.h",
    "content": "#pragma once\n\n#include <utility>\n\ntemplate<auto TMethod, class T>\nclass Delegate\n{\npublic:\n    explicit Delegate(T* callee)\n        : fpCallee(callee)\n    {}\n    template <typename... Args>\n    decltype(auto) operator()(Args&&... xs) const\n    {\n        return (fpCallee->*TMethod)(std::forward<Args>(xs)...);\n    }\n\n    bool operator == (const Delegate& other) const\n    {\n        return fpCallee == other.fpCallee;\n    }\n\n    bool operator != (const Delegate& other) const\n    {\n        return fpCallee != other.fpCallee;\n    }\n\nprivate:\n    T* fpCallee;\n};\n\n\ntemplate<auto TMethod, class T>\ninline auto MakeDelegate(T* ptr)\n{\n    return Delegate<TMethod, T>(ptr);\n}\n\n#define MAKE_DELEGATE(foo, thisPtr) (MakeDelegate<foo>(thisPtr))\n"
  },
  {
    "path": "Player/MemoryMappedFile.h",
    "content": "#pragma once\n\nclass MemoryMappedFile\n{\npublic:\n    MemoryMappedFile()\n        : hFile(INVALID_HANDLE_VALUE)\n        , hFileMapping(NULL)\n        , pData(NULL)\n    {}\n    ~MemoryMappedFile()\n    {\n        if (pData)\n            UnmapViewOfFile(pData);\n        if (hFileMapping)\n            CloseHandle(hFileMapping);\n        if (INVALID_HANDLE_VALUE != hFile)\n            CloseHandle(hFile);\n    }\n    MemoryMappedFile(const MemoryMappedFile&) = delete;\n    MemoryMappedFile& operator=(const MemoryMappedFile&) = delete;\n\n    bool MapFlie(LPCTSTR szFile)\n    {\n        hFile = CreateFile(\n            szFile,                 // pointer to name of the file\n            GENERIC_READ,           // access (read-write) mode\n            FILE_SHARE_READ,        // share mode\n            NULL,                   // pointer to security attributes\n            OPEN_EXISTING,          // how to create\n            FILE_ATTRIBUTE_NORMAL,  // file attributes\n            NULL                    // handle to file with attributes to copy\n        );\n        if (INVALID_HANDLE_VALUE != hFile && GetFileSizeEx(hFile, &fileSize) && fileSize.HighPart == 0)\n        {\n            hFileMapping = CreateFileMapping(\n                hFile,              // handle to file to map\n                NULL,               // optional security attributes\n                PAGE_READONLY,      // protection for mapping object\n                fileSize.HighPart,  // high-order 32 bits of object size\n                fileSize.LowPart,   // low-order 32 bits of object size\n                NULL                // name of file-mapping object\n            );\n            if (NULL != hFileMapping)\n            {\n                pData = MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, (SIZE_T)fileSize.QuadPart);\n                return pData != NULL;\n            }\n        }\n\n        return false;\n    }\n\n    LPVOID data() const { return pData; }\n    LONGLONG size() const { return fileSize.QuadPart; }\n\nprivate:\n    HANDLE hFile;\n    LARGE_INTEGER fileSize;\n    HANDLE hFileMapping;\n    LPVOID pData;\n};\n"
  },
  {
    "path": "Player/OpenSubtitlesFile.cpp",
    "content": "#include \"stdafx.h\"\n\n#include \"OpenSubtitlesFile.h\"\n\n#include <algorithm>\n#include <cctype>\n#include <fstream>\n#include <sstream>\n#include <string>\n\nnamespace {\n\n/*\n *  from mpv/sub/sd_ass.c\n * ass_to_plaintext() was written by wm4 and he says it can be under LGPL\n */\nstd::string ass_to_plaintext(const char *in)\n{\n    std::string result;\n\n    bool in_tag = false;\n    const char *open_tag_pos = nullptr;\n    bool in_drawing = false;\n    while (*in) {\n        if (in_tag) {\n            if (in[0] == '}') {\n                in += 1;\n                in_tag = false;\n            } else if (in[0] == '\\\\' && in[1] == 'p') {\n                in += 2;\n                // Skip text between \\pN and \\p0 tags. A \\p without a number\n                // is the same as \\p0, and leading 0s are also allowed.\n                in_drawing = false;\n                while (in[0] >= '0' && in[0] <= '9') {\n                    if (in[0] != '0')\n                        in_drawing = true;\n                    in += 1;\n                }\n            } else {\n                in += 1;\n            }\n        } else {\n            if (in[0] == '\\\\' && (in[1] == 'N' || in[1] == 'n')) {\n                in += 2;\n                result += '\\n';\n            } else if (in[0] == '\\\\' && in[1] == 'h') {\n                in += 2;\n                result += ' ';\n            } else if (in[0] == '{') {\n                open_tag_pos = in;\n                in += 1;\n                in_tag = true;\n            } else {\n                if (!in_drawing)\n                    result += in[0];\n                in += 1;\n            }\n        }\n    }\n    // A '{' without a closing '}' is always visible.\n    if (in_tag) {\n        result += open_tag_pos;\n    }\n\n    return result;\n}\n\nCString ChangePathExtension(const TCHAR* videoPathName, const TCHAR* ext)\n{\n    CString subRipPathName(videoPathName);\n    PathRemoveExtension(subRipPathName.GetBuffer());\n    subRipPathName.ReleaseBuffer();\n    subRipPathName += ext;\n    return subRipPathName;\n}\n\nbool IsTextUtf8(const std::string& text)\n{\n    auto Src = text.begin();\n    const auto SrcEnd = text.end();\n    while (Src != SrcEnd)\n    {\n        int C = *(Src++);\n        int HighOne = 0; // Number of leftmost '1' bits.\n        for (int Mask = 0x80; Mask != 0 && (C & Mask) != 0; Mask >>= 1)\n            HighOne++;\n        if (HighOne == 1 || HighOne > 4)\n            return false;\n        while (--HighOne > 0)\n            if (Src == SrcEnd || (*(Src++) & 0xc0) != 0x80)\n                return false;\n    }\n    return true;\n}\n\nbool OpenSubRipFile(std::istream& s,\n    bool& unicodeSubtitles,\n    AddIntervalCallback addIntervalCallback)\n{\n    bool autoDetectedUnicode = true;\n    bool ok = false;\n    std::string buffer;\n    while (std::getline(s, buffer))\n    {\n        if (std::find_if(buffer.begin(), buffer.end(), [](unsigned char c) { return !std::isspace(c); })\n            == buffer.end())\n        {\n            continue;\n        }\n\n        if (!std::getline(s, buffer))\n            break;\n\n        int startHr, startMin, startSec, startMsec;\n        int endHr, endMin, endSec, endMsec;\n\n        if (sscanf_s(\n            buffer.c_str(),\n            \"%d:%d:%d,%d --> %d:%d:%d,%d\",\n            &startHr, &startMin, &startSec, &startMsec,\n            &endHr, &endMin, &endSec, &endMsec) != 8)\n        {\n            if (std::find_if(buffer.begin(), buffer.end(), [](unsigned char c) { return !std::isspace(c); })\n                == buffer.end())\n            {\n                continue;\n            }\n            break;\n        }\n\n        const double start = startHr * 3600 + startMin * 60 + startSec + startMsec / 1000.;\n        const double end = endHr * 3600 + endMin * 60 + endSec + endMsec / 1000.;\n\n        std::string subtitle;\n        while (std::getline(s, buffer)\n            && std::find_if(buffer.begin(), buffer.end(), [](unsigned char c) { return !std::isspace(c); })\n            != buffer.end())\n        {\n            subtitle += buffer;\n            subtitle += '\\n'; // The last '\\n' is for aggregating overlapped subtitles (if any)\n        }\n\n        if (!unicodeSubtitles && autoDetectedUnicode)\n            autoDetectedUnicode = IsTextUtf8(subtitle);\n\n        if (!subtitle.empty())\n        {\n            addIntervalCallback(start, end, subtitle);\n            ok = true;\n        }\n    }\n\n    if (!unicodeSubtitles)\n        unicodeSubtitles = autoDetectedUnicode;\n\n    return ok;\n}\n\nbool OpenSubStationAlphaFile(std::istream& s,\n    bool& unicodeSubtitles,\n    AddIntervalCallback addIntervalCallback)\n{\n    bool autoDetectedUnicode = true;\n    bool ok = false;\n    std::string buffer;\n    while (std::getline(s, buffer))\n    {\n        std::istringstream ss(buffer);\n\n        std::getline(ss, buffer, ':');\n\n        if (buffer != \"Dialogue\")\n            continue;\n\n        double start, end;\n        bool skip = false;\n        for (int i = 0; i < 9; ++i) // TODO indices from Format?\n        {\n            std::getline(ss, buffer, ',');\n            if (i == 1 || i == 2)\n            {\n                int hr, min, sec;\n                char msecString[10]{};\n                if (sscanf_s(\n                    buffer.c_str(),\n                    \"%d:%d:%d.%9s\",\n                    &hr, &min, &sec, msecString, (unsigned)_countof(msecString)) != 4)\n                {\n                    return true;\n                }\n\n                double msec = 0;\n                if (const auto msecStringLen = strlen(msecString))\n                {\n                    msec = atoi(msecString) / pow(10, msecStringLen);\n                }\n\n                ((i == 1) ? start : end)\n                    = hr * 3600 + min * 60 + sec + msec;\n            }\n            else if (i == 3 && buffer == \"OP_kar\")\n            {\n                skip = true;\n                break;\n            }\n        }\n\n        if (skip)\n            continue;\n\n        std::getline(ss, buffer, {});\n        std::string subtitle = ass_to_plaintext(buffer.c_str());\n\n        if (!unicodeSubtitles && autoDetectedUnicode)\n            autoDetectedUnicode = IsTextUtf8(subtitle);\n\n        if (!subtitle.empty())\n        {\n            subtitle += '\\n'; // The last '\\n' is for aggregating overlapped subtitles (if any)\n            addIntervalCallback(start, end, subtitle);\n            ok = true;\n        }\n    }\n\n    if (!unicodeSubtitles)\n        unicodeSubtitles = autoDetectedUnicode;\n\n    return ok;\n}\n\ntemplate<char C>\nclass FilterBuf : public std::streambuf\n{\n    char readBuf_;\n    const char* pExternBuf_;\n\n    int_type underflow() override\n    {\n        if (gptr() == &readBuf_)\n            return traits_type::to_int_type(readBuf_);\n\n        for (; *pExternBuf_ == C; ++pExternBuf_);\n\n        if (*pExternBuf_ == '\\0')\n            return traits_type::eof();\n\n        int_type nextChar = *pExternBuf_++;\n\n        readBuf_ = traits_type::to_char_type(nextChar);\n\n        setg(&readBuf_, &readBuf_, &readBuf_ + 1);\n        return traits_type::to_int_type(readBuf_);\n    }\n\npublic:\n    explicit FilterBuf(const char* pExternBuf)\n        : pExternBuf_(pExternBuf)\n    {\n        setg(nullptr, nullptr, nullptr);\n    }\n};\n\nbool OpenSubFile(\n    bool(*doOpenSubFile)(std::istream&, bool&, AddIntervalCallback),\n    const TCHAR* videoPathName,\n    bool& unicodeSubtitles,\n    AddIntervalCallback addIntervalCallback)\n{\n    do\n    {\n        std::ifstream s(videoPathName);\n        if (!s)\n            return false;\n\n        unicodeSubtitles = false;\n        const char ch = s.peek();\n        if (ch == char(0xFF))\n        {\n            s.get();\n            if (char(s.peek()) == char(0xFE))\n            {\n                break; // go to unicode part\n            }\n            s.unget();\n        }\n        else if (ch == char(0xEF))\n        {\n            s.get();\n            if (char(s.peek()) == char(0xBB))\n            {\n                s.get();\n                if (char(s.peek()) == char(0xBF))\n                {\n                    unicodeSubtitles = true;\n                }\n                else\n                {\n                    s.unget();\n                    s.unget();\n                }\n            }\n            else\n                s.unget();\n        }\n\n        return doOpenSubFile(s, unicodeSubtitles, addIntervalCallback);\n\n    } while (false);\n\n    std::ifstream s(videoPathName, std::ios::binary);\n    if (!s)\n        return false;\n\n    s.seekg(0, std::ios::end);\n    const auto size = static_cast<size_t>(s.tellg()) - 2;\n    s.seekg(2, std::ios::beg);\n\n    std::wstring str(size / 2 + 1, L'\\0');\n\n    s.read(static_cast<char*>(static_cast<void*>(str.data())), size);\n\n    ATL::CW2A text(str.c_str(), CP_UTF8);\n    FilterBuf<'\\r'> buf(text);\n\n    std::iostream ss(&buf);\n\n    unicodeSubtitles = true;\n\n    return doOpenSubFile(ss, unicodeSubtitles, addIntervalCallback);\n}\n\n} // namespace\n\nbool OpenSubtitlesFile(const TCHAR* videoPathName,\n    bool& unicodeSubtitles,\n    AddIntervalCallback addIntervalCallback)\n{\n    const auto extension = PathFindExtension(videoPathName);\n    if (!_tcsicmp(extension, _T(\".srt\"))\n        && OpenSubFile(OpenSubRipFile, videoPathName, unicodeSubtitles, addIntervalCallback))\n    {\n        return true;\n    }\n\n    return OpenSubFile(OpenSubStationAlphaFile, videoPathName, unicodeSubtitles, addIntervalCallback);\n}\n\nbool OpenMatchingSubtitlesFile(const TCHAR* videoPathName,\n    bool& unicodeSubtitles,\n    AddIntervalCallback addIntervalCallback)\n{\n    for (auto ext : { _T(\".ass\"), _T(\".ssa\") })\n    {\n        if (OpenSubFile(OpenSubStationAlphaFile, ChangePathExtension(videoPathName, ext), unicodeSubtitles, addIntervalCallback))\n            return true;\n    }\n\n    const auto ext = ChangePathExtension(videoPathName, _T(\".srt\"));\n    return OpenSubFile(OpenSubRipFile, ext, unicodeSubtitles, addIntervalCallback)\n        || OpenSubFile(OpenSubStationAlphaFile, ext, unicodeSubtitles, addIntervalCallback);\n}\n"
  },
  {
    "path": "Player/OpenSubtitlesFile.h",
    "content": "#pragma once\n\n#include <tchar.h>\n#include <functional>\n#include <string>\n\ntypedef std::function<void(double, double, const std::string&)> AddIntervalCallback;\n\n\nbool OpenSubtitlesFile(const TCHAR* videoPathName,\n    bool& unicodeSubtitles,\n    AddIntervalCallback addIntervalCallback);\n\nbool OpenMatchingSubtitlesFile(const TCHAR* videoPathName,\n    bool& unicodeSubtitles,\n    AddIntervalCallback addIntervalCallback);\n"
  },
  {
    "path": "Player/Player.cpp",
    "content": "\n// Player.cpp : Defines the class behaviors for the application.\n//\n\n#include \"stdafx.h\"\n#include \"afxwinappex.h\"\n#include \"afxdialogex.h\"\n#include \"Player.h\"\n#include \"MainFrm.h\"\n\n#include \"PlayerDoc.h\"\n#include \"PlayerView.h\"\n#include \"PlayerViewD2D.h\"\n\n#include \"I420Effect.h\"\n\n#include \"AsyncGetUrlUnderMouseCursor.h\"\n\n#include \"YouTuber.h\"\n\n#include \"version.h\"\n\n#include <boost/log/sinks/debug_output_backend.hpp>\n#include <boost/log/sinks/sync_frontend.hpp>\n#include <boost/log/core/core.hpp>\n#include <boost/log/utility/setup/common_attributes.hpp>\n\n#include <boost/log/expressions.hpp>\n\n#include <boost/log/trivial.hpp>\n\n#include <boost/log/support/date_time.hpp>\n\n#include <zlib.h>\n\n#ifdef _DEBUG\n#define new DEBUG_NEW\n#endif\n\n//#define USE_DIRECT2D_VIEW\n\nnamespace {\n\n// https://www.experts-exchange.com/articles/3189/In-Memory-Compression-and-Decompression-Using-ZLIB.html\nint GetMaxCompressedLen(int nLenSrc)\n{\n    int n16kBlocks = (nLenSrc + 16383) / 16384; // round up any fraction of a block\n    return (nLenSrc + 6 + (n16kBlocks * 5));\n}\n\nint CompressData(const BYTE* abSrc, int nLenSrc, BYTE* abDst, int nLenDst)\n{\n    z_stream zInfo { };\n    zInfo.total_in = zInfo.avail_in = nLenSrc;\n    zInfo.total_out = zInfo.avail_out = nLenDst;\n    zInfo.next_in = const_cast<BYTE*>(abSrc);\n    zInfo.next_out = abDst;\n\n    int nRet = -1;\n    int nErr = deflateInit(&zInfo, Z_BEST_COMPRESSION); // zlib function\n    if (nErr == Z_OK) {\n        nErr = deflate(&zInfo, Z_FINISH);              // zlib function\n        if (nErr == Z_STREAM_END) {\n            nRet = zInfo.total_out;\n        }\n    }\n    deflateEnd(&zInfo);    // zlib function\n    return nRet;\n}\n\nint UncompressData(const BYTE* abSrc, int nLenSrc, BYTE* abDst, int nLenDst)\n{\n    z_stream zInfo { };\n    zInfo.total_in = zInfo.avail_in = nLenSrc;\n    zInfo.total_out = zInfo.avail_out = nLenDst;\n    zInfo.next_in = const_cast<BYTE*>(abSrc);\n    zInfo.next_out = abDst;\n\n    int nRet = -1;\n    int nErr = inflateInit(&zInfo);               // zlib function\n    if (nErr == Z_OK) {\n        nErr = inflate(&zInfo, Z_FINISH);     // zlib function\n        if (nErr == Z_STREAM_END) {\n            nRet = zInfo.total_out;\n        }\n    }\n    inflateEnd(&zInfo);   // zlib function\n    return nRet; // -1 or len of output\n}\n\nvoid init_logging()\n{\n    namespace expr = boost::log::expressions;\n\n    boost::log::add_common_attributes();\n\n    auto core = boost::log::core::get();\n\n    // Create the sink. The backend requires synchronization in the frontend.\n    auto sink(boost::make_shared<boost::log::sinks::synchronous_sink<boost::log::sinks::debug_output_backend>>());\n\n    sink->set_formatter(expr::stream\n        //<< '[' << expr::format_date_time< boost::posix_time::ptime >(\"TimeStamp\", \"%H:%M:%S.%f\") << ']'\n        << expr::if_(expr::has_attr(\"Severity\"))\n        [\n            expr::stream << '[' << expr::attr< boost::log::trivial::severity_level >(\"Severity\") << ']'\n        ]\n        << expr::if_(expr::has_attr(\"Channel\"))\n        [\n            expr::stream << '[' << expr::attr< std::string >(\"Channel\") << ']'\n        ]\n        << expr::smessage << '\\n');\n\n    // Set the special filter to the frontend\n    // in order to skip the sink when no debugger is available\n    //sink->set_filter(expr::is_debugger_present());\n\n    core->add_sink(sink);\n}\n\nclass PlayerCommandLineInfo : public CCommandLineInfo\n{\npublic:\n    bool m_bCheckPython = false;\nprivate:\n    void ParseParam(const TCHAR* pszParam, BOOL bFlag, BOOL bLast) override\n    {\n        if (bFlag && _tcsicmp(pszParam, _T(\"check_python\")) == 0) {\n            m_bCheckPython = true;\n            return;\n        }\n        CCommandLineInfo::ParseParam(pszParam, bFlag, bLast);\n    }\n\n};\n\n} // namespace\n\n\n// CPlayerApp\n\nBEGIN_MESSAGE_MAP(CPlayerApp, CWinAppEx)\n    ON_COMMAND(ID_APP_ABOUT, &CPlayerApp::OnAppAbout)\n    // Standard file based document commands\n    ON_COMMAND(ID_FILE_NEW, &CWinAppEx::OnFileNew)\n    ON_COMMAND(ID_FILE_OPEN, &CWinAppEx::OnFileOpen)\n    // Standard print setup command\n    ON_COMMAND(ID_FILE_PRINT_SETUP, &CWinAppEx::OnFilePrintSetup)\n    ON_THREAD_MESSAGE(WM_ON_ASYNC_URL, &CPlayerApp::OnAsyncUrl)\nEND_MESSAGE_MAP()\n\n\n// CPlayerApp construction\n\nCPlayerApp::CPlayerApp()\n{\n    // support Restart Manager\n    m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_ALL_ASPECTS;\n#ifdef _MANAGED\n    // If the application is built using Common Language Runtime support (/clr):\n    //     1) This additional setting is needed for Restart Manager support to work properly.\n    //     2) In your project, you must add a reference to System.Windows.Forms in order to build.\n    System::Windows::Forms::Application::SetUnhandledExceptionMode(System::Windows::Forms::UnhandledExceptionMode::ThrowException);\n#endif\n\n    // TODO: replace application ID string below with unique ID string; recommended\n    // format for string is CompanyName.ProductName.SubProduct.VersionInformation\n    SetAppID(_T(\"Player.AppID.NoVersion\"));\n\n    // Place all significant initialization in InitInstance\n    init_logging();\n}\n\n// The one and only CPlayerApp object\n\nCPlayerApp theApp;\n\n\n// CPlayerApp initialization\n\nBOOL CPlayerApp::InitInstance()\n{\n    CPane::m_bHandleMinSize = true;\n\n    // InitCommonControlsEx() is required on Windows XP if an application\n    // manifest specifies use of ComCtl32.dll version 6 or later to enable\n    // visual styles.  Otherwise, any window creation will fail.\n    INITCOMMONCONTROLSEX InitCtrls;\n    InitCtrls.dwSize = sizeof(InitCtrls);\n    // Set this to include all the common control classes you want to use\n    // in your application.\n    InitCtrls.dwICC = ICC_STANDARD_CLASSES;\n    InitCommonControlsEx(&InitCtrls);\n\n    __super::InitInstance();\n\n    AfxOleInit();\n\n    // Parse command line for standard shell commands, DDE, file open\n    PlayerCommandLineInfo cmdInfo;\n    ParseCommandLine(cmdInfo);\n    if (cmdInfo.m_bCheckPython)\n    {\n        CheckPython();\n        return FALSE;\n    }\n    if (cmdInfo.m_nShellCommand == CCommandLineInfo::FileNew)\n    {\n        AsyncGetUrlUnderMouseCursor();\n    }\n\n#ifdef USE_DIRECT2D_VIEW\n    if (AfxGetD2DState()->GetDirect2dFactory() == NULL)\n    {\n        return FALSE;\n    }\n    HRESULT hr_create = I420Effect::Register(static_cast<ID2D1Factory1*>(AfxGetD2DState()->GetDirect2dFactory()));\n    if (FAILED(hr_create))\n    {\n        return FALSE;\n    }\n#endif // USE_DIRECT2D_VIEW\n\n    EnableTaskbarInteraction(FALSE);\n\n    // AfxInitRichEdit2() is required to use RichEdit control\t\n    // AfxInitRichEdit2();\n\n    // Standard initialization\n    // If you are not using these features and wish to reduce the size\n    // of your final executable, you should remove from the following\n    // the specific initialization routines you do not need\n    // Change the registry key under which our settings are stored\n    // TODO: You should modify this string to be something appropriate\n    // such as the name of your company or organization\n    SetRegistryKey(_T(\"FFMPEG Player\"));\n    LoadStdProfileSettings(_AFX_MRU_MAX_COUNT);  // Load standard INI file options (including MRU)\n\n    // MFC Feature Pack\n    InitContextMenuManager();\n    InitShellManager();\n    InitKeyboardManager();\n    InitTooltipManager();\n    CMFCToolTipInfo ttParams;\n    ttParams.m_bVislManagerTheme = TRUE;\n    theApp.GetTooltipManager()->\n        SetTooltipParams(AFX_TOOLTIP_TYPE_ALL,\n            RUNTIME_CLASS(CMFCToolTipCtrl), &ttParams);\n\n    // Register the application's document templates.  Document templates\n    //  serve as the connection between documents, frame windows and views\n    auto* pDocTemplate = new CSingleDocTemplate(\n        IDR_MAINFRAME,\n        RUNTIME_CLASS(CPlayerDoc),\n        RUNTIME_CLASS(CMainFrame),       // main SDI frame window\n#ifdef USE_DIRECT2D_VIEW\n        RUNTIME_CLASS(CPlayerViewD2D));\n#else\n        RUNTIME_CLASS(CPlayerView));\n#endif\n    if (!pDocTemplate) {\n        return FALSE;\n    }\n    AddDocTemplate(pDocTemplate);\n\n    HandleMruList();\n\n    // Dispatch commands specified on the command line.  Will return FALSE if\n    // app was launched with /RegServer, /Register, /Unregserver or /Unregister.\n    if (cmdInfo.m_nShellCommand == CCommandLineInfo::FileOpen)\n    {\n        if (!pDocTemplate->OpenDocumentFile(cmdInfo.m_strFileName))\n        {\n            return FALSE;\n        }\n    }\n    else if (!ProcessShellCommand(cmdInfo)) {\n        return FALSE;\n    }\n\n    // https://stackoverflow.com/a/56079903/10472202\n    //enum { TIME_PERIOD = 1 };\n    //if (timeBeginPeriod(TIME_PERIOD) == TIMERR_NOERROR)\n    //{\n    //    atexit([] { timeEndPeriod(TIME_PERIOD); });\n    //}\n\n    // The one and only window has been initialized, so show and update it\n    m_pMainWnd->ShowWindow(SW_SHOW);\n    m_pMainWnd->UpdateWindow();\n    return TRUE;\n}\n\n// CPlayerApp message handlers\n\n\n// CAboutDlg dialog used for App About\n\nclass CAboutDlg : public CDialogEx\n{\npublic:\n    CAboutDlg();\n\n    BOOL OnInitDialog() override;\n\n    // Dialog Data\n    enum { IDD = IDD_ABOUTBOX };\n\n    CString m_videoProperties;\n\nprotected:\n    void DoDataExchange(CDataExchange* pDX) override;    // DDX/DDV support\n\n// Implementation\nprotected:\n    DECLARE_MESSAGE_MAP()\n};\n\nCAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)\n{\n}\n\nBOOL CAboutDlg::OnInitDialog()\n{\n    ModifyStyleEx(0, WS_EX_LAYERED);\n    SetLayeredWindowAttributes(0, (255 * 75) / 100, LWA_ALPHA);\n#ifdef GIT_COMMIT\n    CString text;\n    GetDlgItemText(IDC_APP_NAME_VERSION, text);\n    text += \" \" BOOST_STRINGIZE(GIT_COMMIT);\n    SetDlgItemText(IDC_APP_NAME_VERSION, text);\n#endif\n    return __super::OnInitDialog();\n}\n\nvoid CAboutDlg::DoDataExchange(CDataExchange* pDX)\n{\n    CDialogEx::DoDataExchange(pDX);\n    DDX_Text(pDX, IDC_VIDEO_PROPERTIES, m_videoProperties);\n}\n\nBEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)\nEND_MESSAGE_MAP()\n\nCPlayerDoc* CPlayerApp::GetPlayerDocument()\n{\n    POSITION pos1 = GetFirstDocTemplatePosition();\n    if (CDocTemplate* templ = GetNextDocTemplate(pos1))\n    {\n        POSITION pos2 = templ->GetFirstDocPosition();\n        return dynamic_cast<CPlayerDoc*>(templ->GetNextDoc(pos2));\n    }\n\n    return nullptr;\n}\n\n\n// App command to run the dialog\nvoid CPlayerApp::OnAppAbout()\n{\n    CAboutDlg aboutDlg;\n\n    if (CPlayerDoc* doc = GetPlayerDocument())\n    {\n        const auto properties = doc->getFrameDecoder()->getProperties();\n        for (const auto& prop : properties)\n        {\n            if (!aboutDlg.m_videoProperties.IsEmpty()) {\n                aboutDlg.m_videoProperties += '\\n';\n            }\n            aboutDlg.m_videoProperties += prop.c_str();\n        }\n    }\n\n    aboutDlg.DoModal();\n}\n\n// CPlayerApp message handlers\n\nvoid CPlayerApp::OnAsyncUrl(WPARAM wParam, LPARAM /*unused*/)\n{\n    CComBSTR url;\n    url.Attach((BSTR)wParam);\n    if (CPlayerDoc* doc = GetPlayerDocument())\n    {\n        doc->OnAsyncUrl(CString(url));\n    }\n}\n\n\nconst TCHAR szMappedAudioFilesEntry[] = _T(\"MappedAudioFiles\");\nconst int MappedAudioFilesEntryVersion = 2;\n\nbool CPlayerApp::GetMappedAudioFiles(CMapStringToString& map)\n{\n    map.RemoveAll();\n\n    LPBYTE pData = nullptr;\n    UINT bytes = 0;\n    if (!GetBinary(szMappedAudioFilesEntry, &pData, &bytes) || bytes == 0) {\n        return false;\n    }\n\n    const auto size = 65536;\n\n    std::vector<BYTE> unpacked(size);\n    int nLen = UncompressData(pData, bytes, unpacked.data(), size);\n\n    delete[] pData;\n\n    CMemFile mf(unpacked.data(), nLen);\n    {\n        CArchive ar(&mf, CArchive::load);\n\n        int version = 0;\n        ar >> version;\n        if (version != MappedAudioFilesEntryVersion) {\n            return false;\n        }\n        map.Serialize(ar);\n    }\n    mf.Detach();\n\n    return true;\n}\n\nvoid CPlayerApp::SetMappedAudioFiles(CMapStringToString& map)\n{\n    CMemFile mf;\n    {\n        CArchive ar(&mf, CArchive::store);\n        ar << MappedAudioFilesEntryVersion;\n\n        map.Serialize(ar);\n    }\n\n    UINT uiDataSize = static_cast<UINT>(mf.GetLength());\n    LPBYTE lpbData = mf.Detach();\n    if (lpbData == nullptr) {\n        return;\n    }\n\n    int nLenDst = GetMaxCompressedLen(uiDataSize);\n    std::vector<BYTE> packed(nLenDst);\n\n    int nLenPacked = CompressData(lpbData, uiDataSize, packed.data(), nLenDst);\n    free(lpbData);\n    if (nLenPacked == -1) {\n        return;  // error\n    }\n\n    WriteBinary(szMappedAudioFilesEntry, packed.data(), nLenPacked);\n}\n\nvoid CPlayerApp::HandleMruList()\n{\n    CMapStringToString oldMappedAudioFiles;\n    GetMappedAudioFiles(oldMappedAudioFiles);\n\n    CMapStringToString newMappedAudioFiles;\n\n    if (m_pRecentFileList != nullptr)\n    {\n        for (int i = m_pRecentFileList->GetSize(); --i >= 0;)\n        {\n            const auto& key = (*m_pRecentFileList)[i];\n            if (_taccess(key, 04) != 0) {\n                m_pRecentFileList->Remove(i);\n            }\n            else\n            {\n                CString value;\n                if (oldMappedAudioFiles.Lookup(key, value)) {\n                    newMappedAudioFiles[key] = value;\n                }\n            }\n        }\n    }\n\n    if (oldMappedAudioFiles.GetSize() != newMappedAudioFiles.GetSize()) {\n        SetMappedAudioFiles(newMappedAudioFiles);\n    }\n}\n\nCString CPlayerApp::GetMappedAudioFile(LPCTSTR key)\n{\n    CMapStringToString mappedAudioFiles;\n    GetMappedAudioFiles(mappedAudioFiles);\n    CString result;\n    mappedAudioFiles.Lookup(key, result);\n    return result;\n}\n\nvoid CPlayerApp::SetMappedAudioFile(LPCTSTR key, LPCTSTR value)\n{\n    CMapStringToString mappedAudioFiles;\n    GetMappedAudioFiles(mappedAudioFiles);\n    mappedAudioFiles[key] = value;\n    SetMappedAudioFiles(mappedAudioFiles);\n}\n"
  },
  {
    "path": "Player/Player.h",
    "content": "\n// Player.h : main header file for the Player application\n//\n#pragma once\n\n#ifndef __AFXWIN_H__\n    #error \"include 'stdafx.h' before including this file for PCH\"\n#endif\n\n#include \"resource.h\"       // main symbols\n\nclass CPlayerDoc;\n\n// CPlayerApp:\n// See Player.cpp for the implementation of this class\n//\n\nclass CPlayerApp : public CWinAppEx\n{\npublic:\n    CPlayerApp();\n\n\n// Overrides\npublic:\n    BOOL InitInstance() override;\n\n    CString GetMappedAudioFile(LPCTSTR key);\n    void SetMappedAudioFile(LPCTSTR key, LPCTSTR value);\n\n// Implementation\n    afx_msg void OnAppAbout();\n    afx_msg void OnAsyncUrl(WPARAM wParam, LPARAM lParam);\n    DECLARE_MESSAGE_MAP()\n\n    CPlayerDoc* GetPlayerDocument();\n\nprivate:\n    bool GetMappedAudioFiles(CMapStringToString& map);\n    void SetMappedAudioFiles(CMapStringToString& map);\n\n    void HandleMruList();\n};\n\nextern CPlayerApp theApp;\n\nenum { ID_FIRST_SUBTITLE = 7000, ID_TRACK1 = 7100 };\n"
  },
  {
    "path": "Player/Player.rc",
    "content": "// Microsoft Visual C++ generated resource script.\n//\n#include \"resource.h\"\n\n#define APSTUDIO_READONLY_SYMBOLS\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 2 resource.\n//\n#ifndef APSTUDIO_INVOKED\n#include \"targetver.h\"\n#endif\n#include \"afxres.h\"\n#include \"verrsrc.h\"\n\n/////////////////////////////////////////////////////////////////////////////\n#undef APSTUDIO_READONLY_SYMBOLS\n\n/////////////////////////////////////////////////////////////////////////////\n// English (United States) resources\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\nLANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US\n#pragma code_page(1252)\n\n#ifdef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// TEXTINCLUDE\n//\n\n1 TEXTINCLUDE \nBEGIN\n    \"resource.h\\0\"\nEND\n\n2 TEXTINCLUDE \nBEGIN\n    \"#ifndef APSTUDIO_INVOKED\\r\\n\"\n    \"#include \"\"targetver.h\"\"\\r\\n\"\n    \"#endif\\r\\n\"\n    \"#include \"\"afxres.h\"\"\\r\\n\"\n    \"#include \"\"verrsrc.h\"\"\\r\\n\"\n    \"\\0\"\nEND\n\n3 TEXTINCLUDE \nBEGIN\n    \"#define _AFX_NO_OLE_RESOURCES\\r\\n\"\n    \"#define _AFX_NO_TRACKER_RESOURCES\\r\\n\"\n    \"#define _AFX_NO_PROPERTY_RESOURCES\\r\\n\"\n    \"\\r\\n\"\n    \"#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\\r\\n\"\n    \"LANGUAGE 9, 1\\r\\n\"\n    \"#include \"\"res\\\\Player.rc2\"\"  // non-Microsoft Visual C++ edited resources\\r\\n\"\n    \"#include \"\"afxres.rc\"\"      // Standard components\\r\\n\"\n    \"#include \"\"afxprint.rc\"\"    // printing/print preview resources\\r\\n\"\n    \"#endif\\r\\n\"\n    \"\\0\"\nEND\n\n1 TEXTINCLUDE \nBEGIN\n    \"resource.h\\0\"\nEND\n\n2 TEXTINCLUDE \nBEGIN\n    \"\\0\"\nEND\n\n3 TEXTINCLUDE \nBEGIN\n    \"\\r\\n\"\n    \"\\0\"\nEND\n\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Icon\n//\n\n// Icon with lowest ID value placed first to ensure application icon\n// remains consistent on all systems.\nIDR_MAINFRAME           ICON                    \"res\\\\Player.ico\"\n\nIDR_PlayerTYPE          ICON                    \"res\\\\PlayerDoc.ico\"\n\nIDI_PAUSE               ICON                    \"res\\\\pause.ico\"\n\nIDI_PLAY                ICON                    \"res\\\\play.ico\"\n\nIDI_AUDIO               ICON                    \"res\\\\audio.ico\"\n\nIDI_AUDIO_OFF           ICON                    \"res\\\\audio_off.ico\"\n\nIDI_FULL_SCREEN         ICON                    \"res\\\\full_screen.ico\"\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Bitmap\n//\n\nIDR_MAINFRAME           BITMAP                  \"res\\\\Toolbar.bmp\"\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Toolbar\n//\n\nIDR_MAINFRAME TOOLBAR 16, 15\nBEGIN\n    BUTTON      ID_FILE_NEW\n    BUTTON      ID_FILE_OPEN\n    BUTTON      ID_FILE_SAVE\n    SEPARATOR\n    BUTTON      ID_EDIT_CUT\n    BUTTON      ID_EDIT_COPY\n    BUTTON      ID_EDIT_PASTE\n    SEPARATOR\n    BUTTON      ID_FILE_PRINT\n    BUTTON      ID_APP_ABOUT\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Menu\n//\n\nIDR_MAINFRAME MENU\nBEGIN\n    POPUP \"&File\"\n    BEGIN\n        MENUITEM \"&New\\tCtrl+N\",                ID_FILE_NEW\n        MENUITEM \"&Open...\\tCtrl+O\",            ID_FILE_OPEN\n        MENUITEM \"&Save\\tCtrl+S\",               ID_FILE_SAVE\n        MENUITEM \"Save Copy &As...\",            ID_FILE_SAVE_COPY_AS\n        MENUITEM \"Using Host Header Override Mode\", ID_USING_HHO\n        MENUITEM SEPARATOR\n        MENUITEM \"Copy URL To Clipboard\",       ID_COPY_URL_TO_CLIPBOARD\n        MENUITEM \"Convert Videos Into Compatible Format\", ID_CONVERT_VIDEOS_INTO_COMPATIBLE_FORMAT\n        MENUITEM SEPARATOR\n        MENUITEM \"Autoplay\",                    ID_AUTOPLAY\n        MENUITEM \"Looping\",                     ID_LOOPING\n        MENUITEM SEPARATOR\n        MENUITEM \"Recent File\",                 ID_FILE_MRU_FILE1, GRAYED\n        MENUITEM SEPARATOR\n        MENUITEM \"E&xit\",                       ID_APP_EXIT\n    END\n    POPUP \"Audio/Video\"\n    BEGIN\n        POPUP \"Audio Track\"\n        BEGIN\n            MENUITEM \"Track 1\",                     ID_TRACK1_DUMMY\n        END\n        POPUP \"Video Speed\"\n        BEGIN\n            MENUITEM \"0.5x\",                        ID_VIDEO_SPEED1\n            MENUITEM \"0.63x\",                       ID_VIDEO_SPEED2\n            MENUITEM \"0.8x\",                        ID_VIDEO_SPEED3\n            MENUITEM \"1x\",                          ID_VIDEO_SPEED4\n            MENUITEM \"1.25x\",                       ID_VIDEO_SPEED5\n            MENUITEM \"1.6x\",                        ID_VIDEO_SPEED6\n            MENUITEM \"2x\",                          ID_VIDEO_SPEED7\n            MENUITEM \"Nightcore\",                   ID_NIGHTCORE\n        END\n        POPUP \"Orientation\"\n        BEGIN\n            MENUITEM \"Do Nothing\",                  ID_ORIENTATION_DO_NOTHING\n            MENUITEM \"Rotate 90\",                   ID_ORIENTATION_RORATE_90\n            MENUITEM \"Rotate 180\",                  ID_ORIENTATION_RORATE_180\n            MENUITEM \"Rotate 270\",                  ID_ORIENTATION_RORATE_270\n            MENUITEM SEPARATOR\n            MENUITEM \"Horizontal Mirror\",           ID_ORIENTATION_MIRRORX\n            MENUITEM \"Vertical Mirror\",             ID_ORIENTATION_MIRRORY\n            MENUITEM \"Upend\",                       ID_ORIENTATION_UPEND\n        END\n        MENUITEM \"Video Filter...\",             ID_VIDEO_FILTER\n        MENUITEM SEPARATOR\n        MENUITEM \"Maximal Resolution\",          ID_MAXIMALRESOLUTION\n        MENUITEM \"Hardware Acceleration\",       ID_HW_ACCELERATION\n        MENUITEM \"Super Resolution\",            ID_SUPER_RESOLUTION\n        MENUITEM SEPARATOR\n        MENUITEM \"Open Audio File...\",          ID_OPEN_AUDIO_FILE\n        MENUITEM \"Open Subtitles File...\",      ID_OPENSUBTITLESFILE\n        POPUP \"Open Subtitles\"\n        BEGIN\n            MENUITEM \"Subtitle 1\",                  ID_FIRST_SUBTITLE_DUMMY\n        END\n        MENUITEM \"Fix Encoding\",                ID_FIX_ENCODING\n    END\n    POPUP \"&View\"\n    BEGIN\n        MENUITEM \"&Toolbar\",                    ID_VIEW_TOOLBAR\n        MENUITEM \"&Status Bar\",                 ID_VIEW_STATUS_BAR\n    END\n    POPUP \"&Help\"\n    BEGIN\n        MENUITEM \"&About Player...\",            ID_APP_ABOUT\n    END\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Accelerator\n//\n\nIDR_MAINFRAME ACCELERATORS\nBEGIN\n    \"N\",            ID_FILE_NEW,            VIRTKEY, CONTROL\n    \"O\",            ID_FILE_OPEN,           VIRTKEY, CONTROL\n    \"S\",            ID_FILE_SAVE,           VIRTKEY, CONTROL\n    \"P\",            ID_FILE_PRINT,          VIRTKEY, CONTROL\n    \"Z\",            ID_EDIT_UNDO,           VIRTKEY, CONTROL\n    \"X\",            ID_EDIT_CUT,            VIRTKEY, CONTROL\n    \"C\",            ID_EDIT_COPY,           VIRTKEY, CONTROL\n    \"V\",            ID_EDIT_PASTE,          VIRTKEY, CONTROL\n    VK_BACK,        ID_EDIT_UNDO,           VIRTKEY, ALT\n    VK_DELETE,      ID_EDIT_CUT,            VIRTKEY, SHIFT\n    VK_INSERT,      ID_EDIT_COPY,           VIRTKEY, CONTROL\n    VK_INSERT,      ID_EDIT_PASTE,          VIRTKEY, SHIFT\n    VK_F6,          ID_NEXT_PANE,           VIRTKEY \n    VK_F6,          ID_PREV_PANE,           VIRTKEY, SHIFT\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Dialog\n//\n\nIDD_ABOUTBOX DIALOGEX 0, 0, 341, 178\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"About FFmpeg Player\"\nFONT 8, \"MS Shell Dlg\", 0, 0, 0x1\nBEGIN\n    ICON            IDR_MAINFRAME,IDC_STATIC,9,14,20,20,SS_REALSIZEIMAGE\n    DEFPUSHBUTTON   \"OK\",IDOK,284,158,50,14,WS_GROUP\n    LTEXT           \"FFmpeg Player, Version 1.0\",IDC_APP_NAME_VERSION,178,14,149,8,SS_NOPREFIX\n    LTEXT           \"github.com/aliakseis/FFmpegPlayer\",IDC_STATIC,178,22,114,8\n    LTEXT           \"Icons: www.danieledesantis.net\",IDC_STATIC,178,36,114,8\n    LTEXT           \"www.iconfinder.com/Rudityas\",IDC_STATIC,178,44,97,8\n    LTEXT           \"YouTube: github.com/yt-dlp\",IDC_STATIC,178,58,156,8\n    LTEXT           \"github.com/jdepoix/youtube-transcript-api\",IDC_STATIC,178,66,156,8\n    LTEXT           \"Pitch shifting by Stephan M. Bernsee\",IDC_STATIC,178,80,141,8\n    LTEXT           \"\",IDC_VIDEO_PROPERTIES,178,109,156,48\n    LTEXT           \"Upscaling: github.com/TianZerL/Anime4KCPP\",IDC_STATIC,178,94,156,8\nEND\n\nIDD_DIALOGBAR_PLAYER_CONTROL DIALOGEX 0, 0, 374, 22\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x0\nBEGIN\n    CONTROL         \"\",IDC_PROGRESS_SLIDER,\"msctls_trackbar32\",TBS_TOP | TBS_NOTICKS | WS_TABSTOP,88,4,103,15\n    PUSHBUTTON      \"\",IDC_PLAY_PAUSE,4,0,26,22,BS_ICON\n    PUSHBUTTON      \"\",IDC_AUDIO_ON_OFF,315,0,26,22,BS_ICON\n    CONTROL         \"\",IDC_VOLUME_SLIDER,\"msctls_trackbar32\",TBS_TOP | TBS_NOTICKS | WS_TABSTOP,237,4,74,15\n    LTEXT           \"\",IDC_CURRENT_TIME,39,6,48,8\n    LTEXT           \"\",IDC_TOTAL_TIME,196,6,34,8\n    PUSHBUTTON      \"\",IDC_FULL_SCREEN,345,0,26,22,BS_ICON\n    CONTROL         \"Frame step\",IDC_FRAME_STEP,\"Button\",BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_TABSTOP,252,6,52,10\nEND\n\nIDD_DIALOG_OPEN_URL DIALOGEX 0, 0, 309, 70\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Open URL\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    EDITTEXT        IDC_EDIT_URL,7,19,295,14,ES_AUTOHSCROLL\n    LTEXT           \"Enter a URL to play:\",IDC_STATIC,7,7,66,8\n    EDITTEXT        IDC_EDIT_INPUT_FORMAT,7,49,121,14,ES_AUTOHSCROLL\n    LTEXT           \"Input format (advanced):\",IDC_STATIC,7,37,174,8\n    CONTROL         \"Parse\",IDC_PARSE,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,146,51,34,10\n    DEFPUSHBUTTON   \"OK\",IDOK,198,49,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,252,49,50,14\nEND\n\nIDD_DIALOGBAR_RANGE DIALOGEX 0, 0, 340, 16\nSTYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    PUSHBUTTON      \"Start\",IDC_START,7,1,36,14\n    EDITTEXT        IDC_EDIT_START,46,1,52,14,ES_AUTOHSCROLL\n    PUSHBUTTON      \"X\",IDC_START_RESET,101,1,16,14\n    PUSHBUTTON      \"End\",IDC_END,122,1,36,14\n    EDITTEXT        IDC_EDIT_END,161,1,52,14,ES_AUTOHSCROLL\n    PUSHBUTTON      \"X\",IDC_END_RESET,216,1,16,14\n    CONTROL         \"Lossless Cut\",IDC_LOSSLESS_CUT,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,238,3,55,10\n    PUSHBUTTON      \"Save as\",ID_FILE_SAVE_COPY_AS,293,1,40,14\nEND\n\nIDD_DIALOG_VIDEO_FILTER DIALOGEX 0, 0, 310, 122\nSTYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU\nCAPTION \"Enter Video Filter:\"\nFONT 8, \"MS Shell Dlg\", 400, 0, 0x1\nBEGIN\n    DEFPUSHBUTTON   \"OK\",IDOK,199,101,50,14\n    PUSHBUTTON      \"Cancel\",IDCANCEL,253,101,50,14\n    EDITTEXT        IDC_VIDEO_FILTER,7,7,296,86,ES_MULTILINE\n    CONTROL         \"Enable video filter\",IDC_ENABLE_VIDEO_FILTER,\"Button\",BS_AUTOCHECKBOX | WS_TABSTOP,7,100,74,10\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// RCDATA\n//\n\nIDR_LAUNCH              RCDATA                  \"res\\\\launch.mkv\"\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// Version\n//\n\nVS_VERSION_INFO VERSIONINFO\n FILEVERSION 1,0,0,1\n PRODUCTVERSION 1,0,0,1\n FILEFLAGSMASK 0x3fL\n#ifdef _DEBUG\n FILEFLAGS 0x1L\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS 0x40004L\n FILETYPE 0x1L\n FILESUBTYPE 0x0L\nBEGIN\n    BLOCK \"StringFileInfo\"\n    BEGIN\n        BLOCK \"040904B0\"\n        BEGIN\n            VALUE \"CompanyName\", \"Sanko\"\n            VALUE \"FileDescription\", \"FFmpeg Player\"\n            VALUE \"FileVersion\", \"1.0.0.1\"\n            VALUE \"InternalName\", \"Player.exe\"\n            VALUE \"LegalCopyright\", \" 2015-2021 Sanko.  All rights reserved.\"\n            VALUE \"OriginalFilename\", \"Player.exe\"\n            VALUE \"ProductName\", \"FFmpeg Player\"\n            VALUE \"ProductVersion\", \"1.0.0.1\"\n        END\n    END\n    BLOCK \"VarFileInfo\"\n    BEGIN\n        VALUE \"Translation\", 0x409, 1200\n    END\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// DESIGNINFO\n//\n\n#ifdef APSTUDIO_INVOKED\nGUIDELINES DESIGNINFO\nBEGIN\n    IDD_ABOUTBOX, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 334\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 171\n    END\n\n    IDD_DIALOGBAR_PLAYER_CONTROL, DIALOG\n    BEGIN\n        RIGHTMARGIN, 365\n        TOPMARGIN, 7\n    END\n\n    IDD_DIALOG_OPEN_URL, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 302\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 63\n    END\n\n    IDD_DIALOGBAR_RANGE, DIALOG\n    BEGIN\n        RIGHTMARGIN, 333\n    END\n\n    IDD_DIALOG_VIDEO_FILTER, DIALOG\n    BEGIN\n        LEFTMARGIN, 7\n        RIGHTMARGIN, 303\n        TOPMARGIN, 7\n        BOTTOMMARGIN, 115\n    END\nEND\n#endif    // APSTUDIO_INVOKED\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// AFX_DIALOG_LAYOUT\n//\n\nIDD_DIALOGBAR_PLAYER_CONTROL AFX_DIALOG_LAYOUT\nBEGIN\n    0,\n    0, 50, 100, 0,\n    0, 50, 0, 0,\n    100, 50, 0, 0,\n    100, 50, 0, 0,\n    0, 50, 0, 0,\n    100, 50, 0, 0,\n    100, 50, 0, 0,\n    100, 50, 0, 0\nEND\n\nIDD_DIALOGBAR_RANGE AFX_DIALOG_LAYOUT\nBEGIN\n    0,\n    25, 50, 0, 0,\n    25, 50, 0, 0,\n    25, 50, 0, 0,\n    50, 50, 0, 0,\n    50, 50, 0, 0,\n    50, 50, 0, 0,\n    75, 50, 0, 0,\n    75, 50, 0, 0\nEND\n\nIDD_DIALOG_OPEN_URL AFX_DIALOG_LAYOUT\nBEGIN\n    0\nEND\n\nIDD_ABOUTBOX AFX_DIALOG_LAYOUT\nBEGIN\n    0\nEND\n\nIDD_DIALOG_VIDEO_FILTER AFX_DIALOG_LAYOUT\nBEGIN\n    0\nEND\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// String Table\n//\n\nSTRINGTABLE\nBEGIN\n    IDR_MAINFRAME           \"Player\\n\\nPlayer\\n\\n\\nPlayer.Document\\nPlayer.Document\"\n    IDS_TOOLBAR_CUSTOMIZE   \"Customize...\"\n    IDS_PLAYER_CONTROL      \"Player Control\"\n    IDS_RANGE               \"Range\"\n    IDS_PAUSE               \"Pause\"\n    IDS_PLAY                \"Play\"\nEND\n\nSTRINGTABLE\nBEGIN\n    AFX_IDS_APP_TITLE       \"Player\"\n    AFX_IDS_IDLEMESSAGE     \"Ready\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_INDICATOR_EXT        \"EXT\"\n    ID_INDICATOR_CAPS       \"CAP\"\n    ID_INDICATOR_NUM        \"NUM\"\n    ID_INDICATOR_SCRL       \"SCRL\"\n    ID_INDICATOR_OVR        \"OVR\"\n    ID_INDICATOR_REC        \"REC\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_FILE_NEW             \"Create a new document\\nNew\"\n    ID_FILE_OPEN            \"Open an existing document\\nOpen\"\n    ID_FILE_CLOSE           \"Close the active document\\nClose\"\n    ID_FILE_SAVE            \"Save the active document\\nSave\"\n    ID_FILE_SAVE_AS         \"Save the active document with a new name\\nSave As\"\n    ID_FILE_PAGE_SETUP      \"Change the printing options\\nPage Setup\"\n    ID_FILE_PRINT_SETUP     \"Change the printer and printing options\\nPrint Setup\"\n    ID_FILE_PRINT           \"Print the active document\\nPrint\"\n    ID_FILE_PRINT_DIRECT    \"Print the active document using current options\\nQuick Print\"\n    ID_FILE_PRINT_PREVIEW   \"Display full pages\\nPrint Preview\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_APP_ABOUT            \"Display program information, version number and copyright\\nAbout\"\n    ID_APP_EXIT             \"Quit the application; prompts to save documents\\nExit\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_FILE_MRU_FILE1       \"Open this document\"\n    ID_FILE_MRU_FILE2       \"Open this document\"\n    ID_FILE_MRU_FILE3       \"Open this document\"\n    ID_FILE_MRU_FILE4       \"Open this document\"\n    ID_FILE_MRU_FILE5       \"Open this document\"\n    ID_FILE_MRU_FILE6       \"Open this document\"\n    ID_FILE_MRU_FILE7       \"Open this document\"\n    ID_FILE_MRU_FILE8       \"Open this document\"\n    ID_FILE_MRU_FILE9       \"Open this document\"\n    ID_FILE_MRU_FILE10      \"Open this document\"\n    ID_FILE_MRU_FILE11      \"Open this document\"\n    ID_FILE_MRU_FILE12      \"Open this document\"\n    ID_FILE_MRU_FILE13      \"Open this document\"\n    ID_FILE_MRU_FILE14      \"Open this document\"\n    ID_FILE_MRU_FILE15      \"Open this document\"\n    ID_FILE_MRU_FILE16      \"Open this document\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_NEXT_PANE            \"Switch to the next window pane\\nNext Pane\"\n    ID_PREV_PANE            \"Switch back to the previous window pane\\nPrevious Pane\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_WINDOW_SPLIT         \"Split the active window into panes\\nSplit\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_EDIT_CLEAR           \"Erase the selection\\nErase\"\n    ID_EDIT_CLEAR_ALL       \"Erase everything\\nErase All\"\n    ID_EDIT_COPY            \"Copy the selection and put it on the Clipboard\\nCopy\"\n    ID_EDIT_CUT             \"Cut the selection and put it on the Clipboard\\nCut\"\n    ID_EDIT_FIND            \"Find the specified text\\nFind\"\n    ID_EDIT_PASTE           \"Insert Clipboard contents\\nPaste\"\n    ID_EDIT_REPEAT          \"Repeat the last action\\nRepeat\"\n    ID_EDIT_REPLACE         \"Replace specific text with different text\\nReplace\"\n    ID_EDIT_SELECT_ALL      \"Select the entire document\\nSelect All\"\n    ID_EDIT_UNDO            \"Undo the last action\\nUndo\"\n    ID_EDIT_REDO            \"Redo the previously undone action\\nRedo\"\nEND\n\nSTRINGTABLE\nBEGIN\n    ID_VIEW_TOOLBAR         \"Show or hide the toolbar\\nToggle ToolBar\"\n    ID_VIEW_STATUS_BAR      \"Show or hide the status bar\\nToggle Status Bar\"\nEND\n\nSTRINGTABLE\nBEGIN\n    AFX_IDS_SCSIZE          \"Change the window size\"\n    AFX_IDS_SCMOVE          \"Change the window position\"\n    AFX_IDS_SCMINIMIZE      \"Reduce the window to an icon\"\n    AFX_IDS_SCMAXIMIZE      \"Enlarge the window to full size\"\n    AFX_IDS_SCNEXTWINDOW    \"Switch to the next document window\"\n    AFX_IDS_SCPREVWINDOW    \"Switch to the previous document window\"\n    AFX_IDS_SCCLOSE         \"Close the active window and prompts to save the documents\"\nEND\n\nSTRINGTABLE\nBEGIN\n    AFX_IDS_SCRESTORE       \"Restore the window to normal size\"\n    AFX_IDS_SCTASKLIST      \"Activate Task List\"\nEND\n\nSTRINGTABLE\nBEGIN\n    AFX_IDS_PICTYPE_ICON    \"Close print preview mode\\nCancel Preview\"\nEND\n\n#endif    // English (United States) resources\n/////////////////////////////////////////////////////////////////////////////\n\n\n\n#ifndef APSTUDIO_INVOKED\n/////////////////////////////////////////////////////////////////////////////\n//\n// Generated from the TEXTINCLUDE 3 resource.\n//\n#define _AFX_NO_OLE_RESOURCES\n#define _AFX_NO_TRACKER_RESOURCES\n#define _AFX_NO_PROPERTY_RESOURCES\n\n#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\nLANGUAGE 9, 1\n#include \"res\\Player.rc2\"  // non-Microsoft Visual C++ edited resources\n#include \"afxres.rc\"      // Standard components\n#include \"afxprint.rc\"    // printing/print preview resources\n#endif\n\n/////////////////////////////////////////////////////////////////////////////\n#endif    // not APSTUDIO_INVOKED\n\n"
  },
  {
    "path": "Player/Player.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{C90196CD-7354-4ED4-BFC0-E51A7E1CBE3C}</ProjectGuid>\n    <RootNamespace>Player</RootNamespace>\n    <Keyword>MFCProj</Keyword>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <UseOfMfc>Dynamic</UseOfMfc>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n    <UseOfMfc>Dynamic</UseOfMfc>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <UseOfMfc>Dynamic</UseOfMfc>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <UseOfMfc>Dynamic</UseOfMfc>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ExecutablePath>$(ExecutablePath)</ExecutablePath>\n    <PreBuildEventUseInBuild>true</PreBuildEventUseInBuild>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ExecutablePath>$(ExecutablePath)</ExecutablePath>\n    <PreBuildEventUseInBuild>true</PreBuildEventUseInBuild>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <ExecutablePath>$(ExecutablePath)</ExecutablePath>\n    <PreBuildEventUseInBuild>true</PreBuildEventUseInBuild>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n    <ExecutablePath>$(ExecutablePath)</ExecutablePath>\n    <PreBuildEventUseInBuild>true</PreBuildEventUseInBuild>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <PreprocessorDefinitions>WIN32;_WINDOWS;_HAS_AUTO_PTR_ETC=1;_HAS_FUNCTION_ASSIGN=1;_HAS_OLD_IOSTREAMS_MEMBERS=1;ENABLE_OPENCL;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>..\\audio;..\\video;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.9;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.10;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.11;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.12;..\\networking;..\\Anime4KCPP\\core\\include;..\\core;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <UndefinePreprocessorDefinitions>\n      </UndefinePreprocessorDefinitions>\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <AdditionalDependencies>Winmm.lib;dxva2.lib;d3d9.lib;Oleacc.lib;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\lib\\Python*.lib;%(AdditionalDependencies);OpenCL.lib</AdditionalDependencies>\n      <DelayLoadDLLs>opencl.dll</DelayLoadDLLs>\n      <AdditionalLibraryDirectories>$(INTELOCLSDKROOT)\\lib\\x86\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <ValidateAllParameters>true</ValidateAllParameters>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </Midl>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <PreBuildEvent>\n      <Command>$(ProjectDir)update_version.cmd</Command>\n    </PreBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level4</WarningLevel>\n      <PreprocessorDefinitions>WIN32;_WINDOWS;_HAS_AUTO_PTR_ETC=1;_HAS_FUNCTION_ASSIGN=1;_HAS_OLD_IOSTREAMS_MEMBERS=1;ENABLE_OPENCL;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>..\\audio;..\\video;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.9;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.10;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.11;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.12;..\\networking;..\\Anime4KCPP\\core\\include;..\\core;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <UndefinePreprocessorDefinitions>\n      </UndefinePreprocessorDefinitions>\n      <DisableSpecificWarnings>4996</DisableSpecificWarnings>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <AdditionalDependencies>Winmm.lib;dxva2.lib;d3d9.lib;Oleacc.lib;OpenCL.lib;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\lib\\Python*.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <DelayLoadDLLs>opencl.dll</DelayLoadDLLs>\n      <AdditionalLibraryDirectories>$(INTELOCLSDKROOT)\\lib\\x64\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </Midl>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <PreBuildEvent>\n      <Command>$(ProjectDir)update_version.cmd</Command>\n    </PreBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;_WINDOWS;_HAS_AUTO_PTR_ETC=1;_HAS_FUNCTION_ASSIGN=1;_HAS_OLD_IOSTREAMS_MEMBERS=1;ENABLE_OPENCL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>..\\audio;..\\video;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.9;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.10;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.11;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.12;..\\networking;..\\Anime4KCPP\\core\\include;..\\core;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <UndefinePreprocessorDefinitions>\n      </UndefinePreprocessorDefinitions>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>Winmm.lib;dxva2.lib;d3d9.lib;Oleacc.lib;%(AdditionalDependencies);OpenCL.lib</AdditionalDependencies>\n      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\n      <DelayLoadDLLs>opencl.dll</DelayLoadDLLs>\n      <AdditionalLibraryDirectories>$(INTELOCLSDKROOT)\\lib\\x86\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <ValidateAllParameters>true</ValidateAllParameters>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </Midl>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <PreBuildEvent>\n      <Command>$(ProjectDir)update_version.cmd</Command>\n    </PreBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level4</WarningLevel>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;_WINDOWS;_HAS_AUTO_PTR_ETC=1;_HAS_FUNCTION_ASSIGN=1;_HAS_OLD_IOSTREAMS_MEMBERS=1;ENABLE_OPENCL;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>..\\audio;..\\video;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.9;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.10;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.11;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\python3.12;..\\networking;..\\Anime4KCPP\\core\\include;..\\core;$(VcpkgRoot)\\installed\\$(VcpkgTriplet)\\include\\opencv4;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n      <UndefinePreprocessorDefinitions>\n      </UndefinePreprocessorDefinitions>\n      <LanguageStandard>stdcpp17</LanguageStandard>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>Winmm.lib;dxva2.lib;d3d9.lib;Oleacc.lib;OpenCL.lib;%(AdditionalDependencies)</AdditionalDependencies>\n      <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\n      <DelayLoadDLLs>opencl.dll</DelayLoadDLLs>\n      <AdditionalLibraryDirectories>$(INTELOCLSDKROOT)\\lib\\x64\\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>\n    </Link>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </Midl>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <PreBuildEvent>\n      <Command>$(ProjectDir)update_version.cmd</Command>\n    </PreBuildEvent>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <Text Include=\"ReadMe.txt\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"AsyncGetUrlUnderMouseCursor.h\" />\n    <ClInclude Include=\"ByteStreamBuffer.h\" />\n    <ClInclude Include=\"D3DFONT.H\" />\n    <ClInclude Include=\"DialogBarPlayerControl.h\" />\n    <ClInclude Include=\"DialogBarRange.h\" />\n    <ClInclude Include=\"DialogOpenURL.h\" />\n    <ClInclude Include=\"DialogVideoFilter.h\" />\n    <ClInclude Include=\"EditTime.h\" />\n    <ClInclude Include=\"FrameToHglobal.h\" />\n    <ClInclude Include=\"FrameTransformer.h\" />\n    <ClInclude Include=\"GetClipboardText.h\" />\n    <ClInclude Include=\"HandleFilesSequence.h\" />\n    <ClInclude Include=\"I420Effect.h\" />\n    <ClInclude Include=\"IEraseableArea.h\" />\n    <ClInclude Include=\"ImageUpscale.h\" />\n    <ClInclude Include=\"MainFrm.h\" />\n    <ClInclude Include=\"MakeDelegate.h\" />\n    <ClInclude Include=\"MemoryMappedFile.h\" />\n    <ClInclude Include=\"OpenSubtitlesFile.h\" />\n    <ClInclude Include=\"Player.h\" />\n    <ClInclude Include=\"PlayerDoc.h\" />\n    <ClInclude Include=\"PlayerViewD2D.h\" />\n    <ClInclude Include=\"PlayerView.h\" />\n    <ClInclude Include=\"Resource.h\" />\n    <ClInclude Include=\"SecondsToString.h\" />\n    <ClInclude Include=\"stdafx.h\" />\n    <ClInclude Include=\"StringDifference.h\" />\n    <ClInclude Include=\"targetver.h\" />\n    <ClInclude Include=\"version.h\" />\n    <ClInclude Include=\"YouTuber.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"AsyncGetUrlUnderMouseCursor.cpp\" />\n    <ClCompile Include=\"D3DFONT.CPP\" />\n    <ClCompile Include=\"DialogBarPlayerControl.cpp\" />\n    <ClCompile Include=\"DialogBarRange.cpp\" />\n    <ClCompile Include=\"DialogOpenURL.cpp\" />\n    <ClCompile Include=\"DialogVideoFilter.cpp\" />\n    <ClCompile Include=\"EditTime.cpp\" />\n    <ClCompile Include=\"FrameToHglobal.cpp\" />\n    <ClCompile Include=\"FrameTransformer.cpp\" />\n    <ClCompile Include=\"HandleFilesSequence.cpp\" />\n    <ClCompile Include=\"I420Effect.cpp\" />\n    <ClCompile Include=\"ImageUpscale.cpp\" />\n    <ClCompile Include=\"MainFrm.cpp\" />\n    <ClCompile Include=\"OpenSubtitlesFile.cpp\" />\n    <ClCompile Include=\"Player.cpp\" />\n    <ClCompile Include=\"PlayerDoc.cpp\" />\n    <ClCompile Include=\"PlayerViewD2D.cpp\" />\n    <ClCompile Include=\"PlayerView.cpp\" />\n    <ClCompile Include=\"stdafx.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"StringDifference.cpp\" />\n    <ClCompile Include=\"YouTuber.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"Player.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"res\\launch.mkv\" />\n    <None Include=\"res\\Player.rc2\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"res\\audio.ico\" />\n    <Image Include=\"res\\audio_off.ico\" />\n    <Image Include=\"res\\full_screen.ico\" />\n    <Image Include=\"res\\pause.ico\" />\n    <Image Include=\"res\\play.ico\" />\n    <Image Include=\"res\\Player.ico\" />\n    <Image Include=\"res\\PlayerDoc.ico\" />\n    <Image Include=\"res\\Toolbar.bmp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <FxCompile Include=\"I420Effect_PS.hlsl\">\n      <ShaderType Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Pixel</ShaderType>\n      <ShaderType Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Pixel</ShaderType>\n      <ShaderType Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Pixel</ShaderType>\n      <ShaderType Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Pixel</ShaderType>\n      <HeaderFileOutput Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">I420Effect_PS.h</HeaderFileOutput>\n      <HeaderFileOutput Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">I420Effect_PS.h</HeaderFileOutput>\n      <HeaderFileOutput Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">I420Effect_PS.h</HeaderFileOutput>\n      <HeaderFileOutput Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">I420Effect_PS.h</HeaderFileOutput>\n      <VariableName Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">I420Effect_ByteCode</VariableName>\n      <VariableName Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">I420Effect_ByteCode</VariableName>\n      <VariableName Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">I420Effect_ByteCode</VariableName>\n      <VariableName Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">I420Effect_ByteCode</VariableName>\n      <ShaderModel Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">4.0_level_9_1</ShaderModel>\n      <ShaderModel Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">4.0_level_9_1</ShaderModel>\n      <ShaderModel Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">4.0_level_9_1</ShaderModel>\n      <ShaderModel Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">4.0_level_9_1</ShaderModel>\n      <ObjectFileOutput Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n      </ObjectFileOutput>\n      <ObjectFileOutput Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n      </ObjectFileOutput>\n      <ObjectFileOutput Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n      </ObjectFileOutput>\n      <ObjectFileOutput Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n      </ObjectFileOutput>\n    </FxCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Anime4KCPPCore.vcxproj\">\n      <Project>{632353e4-4856-38f9-9e74-ed41bd99d7e5}</Project>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\audio\\audio.vcxproj\">\n      <Project>{8b955995-b5ec-41f0-940a-48a6f17bcbb8}</Project>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\networking\\networking.vcxproj\">\n      <Project>{3de6c2d2-fdfc-4745-8282-981df7561405}</Project>\n    </ProjectReference>\n    <ProjectReference Include=\"..\\video\\video.vcxproj\">\n      <Project>{3013c140-ddfc-4bf4-9091-0c4131a0d2a6}</Project>\n    </ProjectReference>\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n  <ProjectExtensions>\n    <VisualStudio>\n      <UserProperties RESOURCE_FILE=\"Player.rc\" />\n    </VisualStudio>\n  </ProjectExtensions>\n</Project>"
  },
  {
    "path": "Player/Player.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <Text Include=\"ReadMe.txt\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"Player.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"stdafx.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"targetver.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MainFrm.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PlayerDoc.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Resource.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"I420Effect.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DialogBarPlayerControl.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MakeDelegate.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"IEraseableArea.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"D3DFONT.H\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DialogOpenURL.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PlayerViewD2D.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"PlayerView.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"YouTuber.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"MemoryMappedFile.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DialogBarRange.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"EditTime.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AsyncGetUrlUnderMouseCursor.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"HandleFilesSequence.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"OpenSubtitlesFile.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"GetClipboardText.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FrameToHglobal.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ImageUpscale.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"version.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ByteStreamBuffer.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"StringDifference.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"SecondsToString.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FrameTransformer.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DialogVideoFilter.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"Player.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"stdafx.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"MainFrm.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PlayerDoc.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"I420Effect.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"DialogBarPlayerControl.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"D3DFONT.CPP\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"DialogOpenURL.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PlayerViewD2D.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"PlayerView.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"YouTuber.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"DialogBarRange.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"EditTime.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"AsyncGetUrlUnderMouseCursor.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"HandleFilesSequence.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"OpenSubtitlesFile.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FrameToHglobal.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ImageUpscale.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"StringDifference.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FrameTransformer.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"DialogVideoFilter.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"Player.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"res\\Player.rc2\">\n      <Filter>Resource Files</Filter>\n    </None>\n    <None Include=\"res\\launch.mkv\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"res\\PlayerDoc.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n    <Image Include=\"res\\Player.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n    <Image Include=\"res\\Toolbar.bmp\">\n      <Filter>Resource Files</Filter>\n    </Image>\n    <Image Include=\"res\\pause.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n    <Image Include=\"res\\play.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n    <Image Include=\"res\\audio.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n    <Image Include=\"res\\audio_off.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n    <Image Include=\"res\\full_screen.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n  </ItemGroup>\n  <ItemGroup>\n    <FxCompile Include=\"I420Effect_PS.hlsl\" />\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "Player/PlayerDoc.cpp",
    "content": "\n// PlayerDoc.cpp : implementation of the CPlayerDoc class\n//\n\n#include \"stdafx.h\"\n// SHARED_HANDLERS can be defined in an ATL project implementing preview, thumbnail\n// and search filter handlers and allows sharing of document code with that project.\n#ifndef SHARED_HANDLERS\n#include \"Player.h\"\n#endif\n\n#include \"PlayerDoc.h\"\n#include \"AudioPlayerImpl.h\"\n#include \"AudioPlayerWasapi.h\"\n#include \"HandleFilesSequence.h\"\n#include \"AudioPitchDecorator.h\"\n#include \"OpenSubtitlesFile.h\"\n#include \"StringDifference.h\"\n\n#include \"DialogOpenURL.h\"\n\n#include \"YouTuber.h\"\n\n#include \"ImageUpscale.h\"\n\n#include \"ByteStreamBuffer.h\"\n\n#include \"DialogVideoFilter.h\"\n#include \"FrameTransformer.h\"\n\n#include <propkey.h>\n#include <memory>\n\n#include <boost/icl/interval_map.hpp>\n#include <boost/algorithm/string.hpp>\n\n#include <algorithm>\n#include <fstream>\n\n#include <string>\n#include <cctype>\n\n#include <atomic>\n#include <filesystem>\n#include <regex>\n\n#include <VersionHelpers.h>\n\n#include <sensapi.h>\n#pragma comment(lib, \"Sensapi\")\n\n#ifdef _DEBUG\n#define new DEBUG_NEW\n#endif\n\n\nnamespace {\n\nvoid SetForegroundWindowInternal(HWND hWnd)\n{\n    if (!hWnd || !::IsWindow(hWnd) || ::SetForegroundWindow(hWnd))\n        return;\n\n    //to unlock SetForegroundWindow we need to imitate pressing [Alt] key\n    bool bPressed = false;\n    if ((::GetAsyncKeyState(VK_MENU) & 0x8000) == 0)\n    {\n        bPressed = true;\n        ::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);\n    }\n\n    ::SetForegroundWindow(hWnd);\n\n    if (bPressed)\n    {\n        ::keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);\n    }\n}\n\nconst RationalNumber videoSpeeds[]\n{\n    { 1, 2 },\n    { 5, 8 },\n    { 4, 5 },\n    { 1, 1 },\n    { 5, 4 },\n    { 8, 5 },\n    { 2, 1 },\n    { 5, 4 }, //nightcore\n};\n\n\nbool IsCalledFromMruList()\n{\n    auto msg = AfxGetCurrentMessage();\n    return msg && msg->message == WM_COMMAND\n        && msg->wParam >= ID_FILE_MRU_FILE1\n        && msg->wParam < ID_FILE_MRU_FILE1 + _AFX_MRU_MAX_COUNT;\n}\n\nCString GetUrlFromUrlFile(LPCTSTR lpszPathName)\n{\n    CString url;\n    auto result = GetPrivateProfileString(\n        _T(\"InternetShortcut\"),\n        _T(\"URL\"),\n        nullptr,\n        url.GetBuffer(4095),\n        4096,\n        lpszPathName);\n    if (!result)\n        return {};\n    url.ReleaseBuffer();\n    return url;\n}\n\nbool PumpMessages()\n{\n    MSG msg;\n    while (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))\n    {\n        if (!AfxGetApp()->PumpMessage())\n        {\n            ::PostQuitMessage(0);\n            return false;\n        }\n    }\n    // let MFC do its idle processing\n    LONG lIdle = 0;\n    while (AfxGetApp()->OnIdle(lIdle++))\n        ;\n\n    return true;\n}\n\nvoid CopyTextToClipboard(const CString& strText)\n{\n#ifdef _UNICODE\n    enum { AFX_TCF_TEXT = CF_UNICODETEXT };\n#else\n    enum { AFX_TCF_TEXT = CF_TEXT };\n#endif\n\n    if (!strText.IsEmpty() && AfxGetMainWnd()->OpenClipboard())\n    {\n        EmptyClipboard();\n\n        const auto textSize = (strText.GetLength() + 1) * sizeof(TCHAR);\n        if (HGLOBAL hClipbuffer = ::GlobalAlloc(GMEM_MOVEABLE, textSize))\n        {\n            if (LPTSTR lpszBuffer = (LPTSTR)GlobalLock(hClipbuffer))\n            {\n                memcpy(lpszBuffer, (LPCTSTR)strText, textSize);\n                ::GlobalUnlock(hClipbuffer);\n            }\n            ::SetClipboardData(AFX_TCF_TEXT, hClipbuffer);\n        }\n        CloseClipboard();\n    }\n}\n\n\nCString getScriptTempPath()\n{\n    TCHAR szTempPath[MAX_PATH];\n    GetTempPath(MAX_PATH, szTempPath);\n    PathAppend(szTempPath, _T(\"ffmpeg-video-conversion-script.cmd\"));\n    return szTempPath;\n}\n\n\n// A function that locks a file for writing but leaves it unmodified\nHANDLE lockFile(LPCTSTR fileName)\n{\n    // Try to open the file with exclusive access\n    HANDLE hFile = CreateFile(fileName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);\n    DWORD dwError = GetLastError();\n\n    // If the file does not exist, create a new one\n    if (dwError == ERROR_FILE_NOT_FOUND)\n    {\n        hFile = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_NEW, 0, NULL);\n        dwError = GetLastError();\n    }\n\n    // If the file is locked by another process, report an error\n    if (dwError == ERROR_SHARING_VIOLATION)\n    {\n        TRACE(\"The file is locked by another process.\\n\");\n        return NULL;\n    }\n\n    // If any other error occurs, report an error\n    if (hFile == INVALID_HANDLE_VALUE)\n    {\n        TRACE(\"Unable to lock the file. Error code: %d.\\n\", dwError);\n        return NULL;\n    }\n\n    // Return the handle to the file\n    return hFile;\n}\n\n// A function that overwrites the file with some stuff\nvoid writeFile(HANDLE hFile, const char* stuff, DWORD size)\n{\n    // Move the file pointer to the beginning of the file\n    SetFilePointer(hFile, 0, NULL, FILE_BEGIN);\n\n    // Write the stuff to the file\n    DWORD dwWritten = 0;\n    WriteFile(hFile, stuff, size, &dwWritten, NULL);\n\n    // Check if the write operation was successful\n    if (dwWritten != size)\n    {\n        TRACE(\"Unable to write to the file.\\n\");\n    }\n\n    // Truncate the file to the current position of the file pointer\n    SetEndOfFile(hFile);\n}\n\n\n// A function that ensures that a CString based file path ends with a file path separator\nvoid ensureSeparator(CString& filePath)\n{\n    // Remove any trailing whitespace from the file path\n    filePath.TrimRight();\n\n    // Get the length of the file path\n    int length = filePath.GetLength();\n\n    // If the file path is not empty\n    if (length > 0)\n    {\n        // Get the last character of the file path\n        const auto lastChar = filePath.GetAt(length - 1);\n\n        // If the last character is not the separator character\n        if (lastChar != _T('\\\\') && lastChar != _T('/'))\n        {\n            // Append the separator character to the file path\n            filePath.Append(_T(\"\\\\\"));\n        }\n    }\n}\n\nbool FileExists(LPCTSTR pszPath, LPCTSTR pszFile) \n{\n    TCHAR szFullPath[MAX_PATH];\n    _tcscpy_s(szFullPath, pszPath);\n    PathAppend(szFullPath, pszFile);\n    return !!PathFileExists(szFullPath);\n}\n\nCString StrikeThrough(const CString& str, bool doIt)\n{\n    if (!doIt)\n        return L\"\\u00A0\\u2714\" + str;\n\n    CString result(L\"\\u00A0\\u2718\");\n    // Iterate over each character in the original string\n    for (int i = 0; i < str.GetLength(); ++i)\n    {\n        auto ch = str[i];\n        if (ch == L' ')\n            ch = L'\\u00A0';\n        // Append the current character\n        result += ch;\n        // Append the Combining Overlay character\n        if (i != str.GetLength() - 1)\n            result += L'\\u0338';\n    }\n    return result;\n}\n\nCString NoBreak(CString s)\n{\n    s.Replace(L' ', L'\\u00A0');\n    return s;\n}\n\nstd::unique_ptr<IAudioPlayer> GetAudioPlayer()\n{\n    if (IsWindowsVistaOrGreater())\n        return std::make_unique<AudioPlayerWasapi>();\n    return std::make_unique<AudioPlayerImpl>();\n}       \n\ntemplate<typename T>\nauto GetAddToSubtitlesMapLambda(T& map)\n{\n    return [&map](double start, double end, const std::string& subtitle) {\n        map->add({ boost::icl::interval<double>::closed(start, end), subtitle });\n    };\n}\n\nCCriticalSection s_csSubtitles;\n\n} // namespace\n\n\nclass CPlayerDoc::SubtitlesMap : public boost::icl::interval_map<double, std::string>\n{\npublic:\n    bool m_unicodeSubtitles = false;\n};\n\n\n// CPlayerDoc\n\nIMPLEMENT_DYNCREATE(CPlayerDoc, CDocument)\n\nBEGIN_MESSAGE_MAP(CPlayerDoc, CDocument)\n    ON_COMMAND_RANGE(ID_TRACK1, ID_TRACK1 + 99, OnAudioTrack)\n    ON_UPDATE_COMMAND_UI_RANGE(ID_TRACK1, ID_TRACK1 + 99, OnUpdateAudioTrack)\n    ON_COMMAND_RANGE(ID_VIDEO_SPEED1, ID_NIGHTCORE, OnVideoSpeed)\n    ON_UPDATE_COMMAND_UI_RANGE(ID_VIDEO_SPEED1, ID_NIGHTCORE, OnUpdateVideoSpeed)\n    ON_COMMAND(ID_AUTOPLAY, &CPlayerDoc::OnAutoplay)\n    ON_UPDATE_COMMAND_UI(ID_AUTOPLAY, &CPlayerDoc::OnUpdateAutoplay)\n    ON_COMMAND(ID_LOOPING, &CPlayerDoc::OnLooping)\n    ON_UPDATE_COMMAND_UI(ID_LOOPING, &CPlayerDoc::OnUpdateLooping)\n    ON_COMMAND(ID_FILE_SAVE_COPY_AS, &CPlayerDoc::OnFileSaveCopyAs)\n    ON_COMMAND(ID_OPENSUBTITLESFILE, &CPlayerDoc::OnOpensubtitlesfile)\n    ON_UPDATE_COMMAND_UI(ID_OPENSUBTITLESFILE, &CPlayerDoc::OnUpdateOpensubtitlesfile)\n    ON_COMMAND(ID_COPY_URL_TO_CLIPBOARD, &CPlayerDoc::OnCopyUrlToClipboard)\n    ON_COMMAND(ID_MAXIMALRESOLUTION, &CPlayerDoc::OnMaximalresolution)\n    ON_UPDATE_COMMAND_UI(ID_MAXIMALRESOLUTION, &CPlayerDoc::OnUpdateMaximalresolution)\n    ON_COMMAND(ID_HW_ACCELERATION, &CPlayerDoc::OnHwAcceleration)\n    ON_UPDATE_COMMAND_UI(ID_HW_ACCELERATION, &CPlayerDoc::OnUpdateHwAcceleration)\n    ON_COMMAND_RANGE(ID_FIRST_SUBTITLE, ID_FIRST_SUBTITLE+99, OnGetSubtitles)\n    ON_UPDATE_COMMAND_UI_RANGE(ID_FIRST_SUBTITLE, ID_FIRST_SUBTITLE + 99, OnUpdateOpensubtitlesfile)\n    ON_COMMAND(ID_SUPER_RESOLUTION, &CPlayerDoc::OnSuperResolution)\n    ON_UPDATE_COMMAND_UI(ID_SUPER_RESOLUTION, &CPlayerDoc::OnUpdateSuperResolution)\n    ON_COMMAND(ID_ORIENTATION_MIRRORX, &CPlayerDoc::OnOrientationMirrorx)\n    ON_UPDATE_COMMAND_UI(ID_ORIENTATION_MIRRORX, &CPlayerDoc::OnUpdateOrientationMirrorx)\n    ON_COMMAND(ID_ORIENTATION_MIRRORY, &CPlayerDoc::OnOrientationMirrory)\n    ON_UPDATE_COMMAND_UI(ID_ORIENTATION_MIRRORY, &CPlayerDoc::OnUpdateOrientationMirrory)\n    ON_COMMAND(ID_ORIENTATION_UPEND, &CPlayerDoc::OnOrientationUpend)\n    ON_UPDATE_COMMAND_UI(ID_ORIENTATION_UPEND, &CPlayerDoc::OnUpdateOrientationUpend)\n    ON_COMMAND(ID_ORIENTATION_DO_NOTHING, &CPlayerDoc::OnOrientationDoNothing)\n    ON_COMMAND(ID_ORIENTATION_RORATE_90, &CPlayerDoc::OnOrientationRotate90)\n    ON_COMMAND(ID_ORIENTATION_RORATE_180, &CPlayerDoc::OnOrientationRotate180)\n    ON_COMMAND(ID_ORIENTATION_RORATE_270, &CPlayerDoc::OnOrientationRotate270)\n    ON_COMMAND(ID_FIX_ENCODING, &CPlayerDoc::OnFixEncoding)\n    ON_UPDATE_COMMAND_UI(ID_FIX_ENCODING, &CPlayerDoc::OnUpdateFixEncoding)\n    ON_COMMAND(ID_CONVERT_VIDEOS_INTO_COMPATIBLE_FORMAT,\n               &CPlayerDoc::OnConvertVideosIntoCompatibleFormat)\n    ON_UPDATE_COMMAND_UI(ID_CONVERT_VIDEOS_INTO_COMPATIBLE_FORMAT,\n                         &CPlayerDoc::OnUpdateConvertVideosIntoCompatibleFormat)\n    ON_COMMAND(ID_OPEN_AUDIO_FILE, &CPlayerDoc::OnOpenAudioFile)\n    ON_UPDATE_COMMAND_UI(ID_OPEN_AUDIO_FILE, &CPlayerDoc::OnUpdateOpenAudioFile)\n    ON_COMMAND(ID_USING_HHO, &CPlayerDoc::OnUsingHostHeaderOverride)\n    ON_UPDATE_COMMAND_UI(ID_USING_HHO, &CPlayerDoc::OnUpdateUsingHostHeaderOverride)\n    ON_COMMAND(ID_VIDEO_FILTER, &CPlayerDoc::OnVideoFilter)\nEND_MESSAGE_MAP()\n\n\nconst TCHAR szPlayerInitFlags[] = _T(\"PlayerInitFlags\");\nconst TCHAR szMaximalResolution[] = _T(\"MaximalResolution\");\nconst TCHAR szUsingHHO[] = _T(\"UsingHHO\");\nconst TCHAR szPlayerState[] = _T(\"PlayerState\");\nconst TCHAR szVideoFilter[] = _T(\"VideoFilter\");\n\n// CPlayerDoc construction/destruction\n\nCPlayerDoc::CPlayerDoc()\n    : m_frameDecoder(\n        GetFrameDecoder(\n            std::make_unique<AudioPitchDecorator>(GetAudioPlayer(),\n            std::bind(&CPlayerDoc::getVideoSpeed, this))))\n{\n    m_frameDecoder->setDecoderListener(this);\n\n    if (auto pApp = AfxGetApp())\n    {\n        m_maximalResolution = !!pApp->GetProfileInt(szPlayerInitFlags, szMaximalResolution, false);\n        m_bUsingHHO = !!pApp->GetProfileInt(szPlayerInitFlags, szUsingHHO, false);\n        m_videoFilter = pApp->GetProfileString(szPlayerState, szVideoFilter, _T(\"\"));\n    }\n}\n\nCPlayerDoc::~CPlayerDoc()\n{\n    if (auto pApp = AfxGetApp())\n    {\n        pApp->WriteProfileInt(szPlayerInitFlags, szMaximalResolution, m_maximalResolution);\n        pApp->WriteProfileInt(szPlayerInitFlags, szUsingHHO, m_bUsingHHO);\n        pApp->WriteProfileString(szPlayerState, szVideoFilter, m_videoFilter);\n    }\n\n    onDestructing();\n\n    ASSERT(framePositionChanged.empty());\n    ASSERT(startTimeUpdated.empty());\n    ASSERT(totalTimeUpdated.empty());\n    ASSERT(currentTimeUpdated.empty());\n\n    ASSERT(rangeStartTimeChanged.empty());\n    ASSERT(rangeEndTimeChanged.empty());\n\n    if (m_hConversionProcess != NULL)\n    {\n        CloseHandle(m_hConversionProcess);\n    }\n}\n\nBOOL CPlayerDoc::OnNewDocument()\n{\n    // (SDI documents will reuse this document)\n    if (AfxGetApp()->m_pMainWnd) // false if the document is being initialized for the first time\n    {\n        CDialogOpenURL dlg;\n        if (dlg.DoModal() == IDOK && !dlg.m_URL.IsEmpty() && CDocument::OnNewDocument())\n        {\n            reset();\n            if (!dlg.m_inputFormt.IsEmpty())\n            {\n                std::string url(CT2A(dlg.m_URL, CP_UTF8));\n                std::string inputFormat(CT2A(dlg.m_inputFormt, CP_UTF8));\n                return openUrl(url, inputFormat);\n            }\n            return openTopLevelUrl(dlg.m_URL, dlg.m_bParse);\n        }\n\n        return false;\n    }\n    else if (GetKeyState(VK_SHIFT) < 0 && GetKeyState(VK_CONTROL) < 0)\n    {\n        HRSRC hFound = ::FindResource(NULL, MAKEINTRESOURCE(IDR_LAUNCH), RT_RCDATA);\n        HGLOBAL hRes = ::LoadResource(NULL, hFound);\n\n        if (!m_frameDecoder->openStream(std::make_unique<ByteStreamBuffer>(\n            (char*)::LockResource(hRes), ::SizeofResource(NULL, hFound))))\n        {\n            return false;\n        }\n\n        m_frameDecoder->play(true);\n        UpdateAllViews(nullptr, UPDATE_HINT_CLOSING);\n        m_frameDecoder->pauseResume();\n        onPauseResume(false);\n        return true;\n    }\n\n    return CDocument::OnNewDocument();\n}\n\nbool CPlayerDoc::openTopLevelUrl(const CString& topLevelUrl, bool force, const CString& pathName)\n{\n    std::string url(CT2A(topLevelUrl, CP_UTF8));\n\n    auto playList = ParsePlaylist(url, force);\n\n    if (!playList.empty())\n    {\n        if (openUrlFromList(playList, pathName))\n            return true;\n    }\n    else if (openUrl(url))\n    {\n        m_playList.clear();\n        m_reopenFunc = [this, url, pathName] {\n            UpdateAllViews(nullptr, UPDATE_HINT_CLOSING);\n            if (openUrl(url) && !pathName.IsEmpty())\n                SetPathName(pathName, FALSE);\n        };\n        return true;\n    }\n\n    return false;\n}\n\nbool CPlayerDoc::openUrl(const std::string& originalUrl, const std::string& inputFormat)\n{\n    std::pair<std::string, std::string> urls;\n\n    if (!inputFormat.empty())\n    {\n        if (!m_frameDecoder->openUrls({ originalUrl }, inputFormat))\n            return false;\n        urls.first = originalUrl;\n    }\n    else\n    {\n        urls = getYoutubeUrl(originalUrl, m_maximalResolution, m_bUsingHHO);\n        if (urls.first.empty() || !((m_maximalResolution && !urls.second.empty())\n            ? m_frameDecoder->openUrls({ urls.first, urls.second }, {}, m_bUsingHHO)\n            : m_frameDecoder->openUrls({ urls.first }, {}, m_bUsingHHO)))\n        {\n            return false;\n        }\n    }\n\n    m_frameDecoder->play(true);\n    m_originalUrl = originalUrl;\n    m_url = urls.first;\n\n    if (m_maximalResolution && !urls.second.empty()) {\n        m_separateFileDiff = std::make_unique<StringDifference>(\n            std::basic_string<TCHAR>(urls.first.begin(), urls.first.end()),\n            std::basic_string<TCHAR>(urls.second.begin(), urls.second.end()));\n    }\n    else {\n        m_separateFileDiff.reset();\n    }\n\n    m_subtitles.reset();\n    m_nightcore = false;\n    ++m_documentGeneration;\n    UpdateAllViews(nullptr, UPDATE_HINT_CLOSING);\n\n    if (inputFormat.empty())\n    {\n        auto map(std::make_unique<SubtitlesMap>());\n        if (getYoutubeTranscripts(originalUrl,\n            [&map](double start, double duration, const std::string& text) {\n            map->add({\n                boost::icl::interval<double>::closed(start, start + duration),\n                boost::algorithm::trim_copy(text) + '\\n' });\n        }))\n        {\n            map->m_unicodeSubtitles = true;\n            m_subtitles = std::move(map);\n        }\n    }\n    m_frameDecoder->pauseResume();\n    onPauseResume(false);\n    return true;\n}\n\nbool CPlayerDoc::openUrlFromList()\n{\n    bool networkCkecked = false;\n\n    while (!m_playList.empty())\n    {\n        auto buffer = m_playList.front();\n        m_playList.pop_front();\n\n        auto playList = ParsePlaylist(buffer, false);\n        if (!playList.empty())\n            m_playList.insert(m_playList.begin(), playList.begin(), playList.end());\n        else if (openUrl(buffer))\n            return true;\n        else if (!networkCkecked && PathIsURLA(buffer.c_str()))\n        {\n            networkCkecked = true;\n            DWORD flags = NETWORK_ALIVE_INTERNET;\n            if (!IsNetworkAlive(&flags))\n            {\n                m_playList.push_front(buffer);\n                return false;\n            }\n        }\n\n        if (!m_playList.empty())\n        {\n            const auto documentGeneration = m_documentGeneration;\n\n            if (!PumpMessages())\n                return false;\n\n            if (m_playList.empty() || documentGeneration != m_documentGeneration)\n                AfxThrowUserException();\n        }\n    }\n    return false;\n}\n\nbool CPlayerDoc::openUrlFromList(const std::vector<std::string>& playList, const CString& pathName)\n{\n    m_playList = { playList.begin(), playList.end() };\n\n    if (openUrlFromList())\n    {\n        m_reopenFunc = [this, playList, pathName] {\n            UpdateAllViews(nullptr, UPDATE_HINT_CLOSING);\n            m_playList = { playList.begin(), playList.end() };\n            if (openUrlFromList() && !pathName.IsEmpty())\n                SetPathName(pathName, FALSE);\n        };\n        return true;\n    }\n    return false;\n}\n\nvoid CPlayerDoc::reset()\n{\n    m_frameDecoder->close();\n    m_subtitles.reset();\n    m_reopenFunc = nullptr;\n\n    m_originalUrl.clear();\n    m_url.clear();\n\n    m_nightcore = false;\n\n    ++m_documentGeneration;\n\n    UpdateAllViews(nullptr, UPDATE_HINT_CLOSING);\n}\n\n// CPlayerDoc serialization\n\nvoid CPlayerDoc::Serialize(CArchive& ar)\n{\n    if (ar.IsStoring())\n    {\n        // TODO: add storing code here\n    }\n    else\n    {\n        // TODO: add loading code here\n    }\n}\n\n#ifdef SHARED_HANDLERS\n\n// Support for thumbnails\nvoid CPlayerDoc::OnDrawThumbnail(CDC& dc, LPRECT lprcBounds)\n{\n    // Modify this code to draw the document's data\n    dc.FillSolidRect(lprcBounds, RGB(255, 255, 255));\n\n    CString strText = _T(\"TODO: implement thumbnail drawing here\");\n    LOGFONT lf;\n\n    CFont* pDefaultGUIFont = CFont::FromHandle((HFONT) GetStockObject(DEFAULT_GUI_FONT));\n    pDefaultGUIFont->GetLogFont(&lf);\n    lf.lfHeight = 36;\n\n    CFont fontDraw;\n    fontDraw.CreateFontIndirect(&lf);\n\n    CFont* pOldFont = dc.SelectObject(&fontDraw);\n    dc.DrawText(strText, lprcBounds, DT_CENTER | DT_WORDBREAK);\n    dc.SelectObject(pOldFont);\n}\n\n// Support for Search Handlers\nvoid CPlayerDoc::InitializeSearchContent()\n{\n    CString strSearchContent;\n    // Set search contents from document's data. \n    // The content parts should be separated by \";\"\n\n    // For example:  strSearchContent = _T(\"point;rectangle;circle;ole object;\");\n    SetSearchContent(strSearchContent);\n}\n\nvoid CPlayerDoc::SetSearchContent(const CString& value)\n{\n    if (value.IsEmpty())\n    {\n        RemoveChunk(PKEY_Search_Contents.fmtid, PKEY_Search_Contents.pid);\n    }\n    else\n    {\n        CMFCFilterChunkValueImpl *pChunk = NULL;\n        ATLTRY(pChunk = new CMFCFilterChunkValueImpl);\n        if (pChunk != NULL)\n        {\n            pChunk->SetTextValue(PKEY_Search_Contents, value, CHUNK_TEXT);\n            SetChunkValue(pChunk);\n        }\n    }\n}\n\n#endif // SHARED_HANDLERS\n\n// CPlayerDoc diagnostics\n\n#ifdef _DEBUG\nvoid CPlayerDoc::AssertValid() const\n{\n    CDocument::AssertValid();\n}\n\nvoid CPlayerDoc::Dump(CDumpContext& dc) const\n{\n    CDocument::Dump(dc);\n}\n#endif //_DEBUG\n\n\n// CPlayerDoc commands\n\n\nBOOL CPlayerDoc::OnOpenDocument(LPCTSTR lpszPathName)\n{\n    const bool shiftAndControlPressed = GetKeyState(VK_SHIFT) < 0\n        && GetKeyState(VK_CONTROL) < 0;\n    if (shiftAndControlPressed && IsCalledFromMruList())\n        return false;\n\n    return openDocument(lpszPathName, shiftAndControlPressed);\n}\n\nBOOL CPlayerDoc::OnSaveDocument(LPCTSTR lpszPathName)\n{\n    const bool isLocalFile = m_url.empty();\n\n    if (isLocalFile && !_tcsicmp(m_strPathName, lpszPathName))\n    {\n        return false;\n    }\n\n    CString source(isLocalFile? m_strPathName : CString(m_url.data(), m_url.length()));\n\n    if (source.IsEmpty())\n        return false;\n\n    const bool transform = m_bOrientationMirrorx || m_bOrientationMirrory || m_bOrientationUpend;\n\n    TCHAR pszPath[MAX_PATH] = { 0 };\n    GetModuleFileName(NULL, pszPath, ARRAYSIZE(pszPath));\n    PathRemoveFileSpec(pszPath);\n    CString strFile;\n    CString strParams;\n    if (isFullFrameRange() && !m_separateFileDiff && !transform && m_videoFilter.IsEmpty())\n    {\n        if (isLocalFile)\n        {\n            return CopyFile(source, lpszPathName, FALSE); // overwrites the existing file\n        }\n\n        strFile = _T(\"HttpDownload.exe\");\n        if (FileExists(pszPath, strFile)) {\n            strParams = source + _T(\" \\\"\") + lpszPathName + _T('\"');\n        }\n        else {\n            strFile = _T(\"curl\");\n            strParams = CString(_T(\"-o \\\"\")) + lpszPathName + _T(\"\\\" \") + source;\n        }\n    }\n    else\n    {\n        CString timeClause;\n        if (!isFullFrameRange())\n        {\n            timeClause.Format(\n                _T(\"-ss %.3f -t %.3f -accurate_seek \"),\n                m_rangeStartTime,\n                m_rangeEndTime - m_rangeStartTime);\n\n        }\n        strFile = _T(\"ffmpeg.exe\");\n        strParams = timeClause + _T(\"-i \\\"\") + source + _T('\"');\n\n        CString mapClause; // will hold -map ... parts\n        const int audioIndex = m_frameDecoder->getAudioTrack();\n        if (audioIndex == 0)\n        {\n            mapClause = _T(\" -map 0:v:0 -map 0:a\");\n        }\n        else\n        {\n            mapClause.Format(_T(\" -map 0:v:0 -map 0:a:%d\"), audioIndex);\n        }\n\n        if (m_separateFileDiff)\n        {\n            const auto s = m_separateFileDiff->patch({ source.GetString(), source.GetString() + source.GetLength() });\n            if (!s.empty()) {\n                // second input (patched audio/video) added\n                strParams += _T(\" \") + timeClause + _T(\"-i \\\"\") + s.c_str() + _T(\"\\\"\");\n\n                // Determine mapping based on preferred audio track index\n                // We assume GetPreferredAudioTrack() returns 0 to mean \"copy all audio tracks\",\n                // non-zero (1-based) to mean \"copy that audio track index\" from the second input\n                if (audioIndex == 0)\n                {\n                    // copy all audio tracks from second input and the first video from first input\n                    mapClause = _T(\" -map 0:v:0 -map 1:a\");\n                }\n                else\n                {\n                    // copy the specified audio track (convert 1-based to 0-based index used by ffmpeg)\n                    mapClause.Format(_T(\" -map 0:v:0 -map 1:a:%d\"), audioIndex);\n                }\n            }\n        }\n\n        const bool streamcopy = (m_losslessCut || isFullFrameRange()) && !transform;\n\n        if (streamcopy)\n            strParams += _T(\" -c copy\");\n\n        // rotation https://webcache.googleusercontent.com/search?q=cache:IiCyGV1Tp7oJ:https://annimon.com/article/3997+\n        CString filterChain;\n\n        if (!m_videoFilter.IsEmpty())\n        {\n            filterChain = m_videoFilter;   // start with user filter\n        }\n\n        // Orientation / rotation filters\n        CString orientationFilter;\n\n        if (m_bOrientationUpend)\n        {\n            if (m_bOrientationMirrory)\n                orientationFilter = m_bOrientationMirrorx ? _T(\"transpose=3\") : _T(\"transpose=1\");\n            else\n                orientationFilter = m_bOrientationMirrorx ? _T(\"transpose=2\") : _T(\"transpose=0\");\n        }\n        else if (m_bOrientationMirrory)\n        {\n            orientationFilter = m_bOrientationMirrorx ? _T(\"hflip,vflip\") : _T(\"vflip\");\n        }\n        else if (m_bOrientationMirrorx)\n        {\n            orientationFilter = _T(\"hflip\");\n        }\n\n        // Combine filters if needed\n        if (!orientationFilter.IsEmpty())\n        {\n            if (!filterChain.IsEmpty())\n                filterChain += _T(\",\") + orientationFilter;\n            else\n                filterChain = orientationFilter;\n        }\n\n        // Add final -vf parameter if any filter exists\n        if (!filterChain.IsEmpty())\n        {\n            strParams += _T(\" -vf \") + filterChain;\n        }\n\n        if (!isFullFrameRange())\n        {\n            strParams += _T(\" -avoid_negative_ts 1 -map_chapters -1\");\n        }\n\n        // Append the mapClause after -avoid_negative_ts / -map_chapters but before re-encode options.\n        if (!mapClause.IsEmpty())\n            strParams += mapClause;\n\n        if (!streamcopy)\n            strParams += _T(\" -q:v 4\");\n\n        strParams += _T(\" -y \\\"\");\n        strParams += lpszPathName;\n        strParams += _T('\"');\n        TRACE(_T(\"FFmpeg parameters generated: %s\\n\"), static_cast<LPCTSTR>(strParams));\n    }\n    const  auto result = ShellExecute(NULL, NULL, strFile, strParams, pszPath, SW_MINIMIZE);\n    return int(result) > 32;\n}\n\n\nbool CPlayerDoc::openDocument(LPCTSTR lpszPathName, bool openSeparateFile /*= false*/)\n{\n    if (!openSeparateFile)\n        reset();\n\n    CString currentDirectory;\n    if (auto fileName = PathFindFileName(lpszPathName))\n    {\n        currentDirectory = CString(lpszPathName, fileName - lpszPathName);\n        SetCurrentDirectory(currentDirectory);\n    }\n\n    const auto extension = PathFindExtension(lpszPathName);\n    if (!_tcsicmp(extension, _T(\".lst\")))\n    {\n        std::ifstream s(lpszPathName);\n        if (!s)\n            return false;\n        m_playList.clear();\n        std::string buffer;\n        while (std::getline(s, buffer))\n        {\n            m_playList.push_back(buffer);\n        }\n\n        if (!openUrlFromList())\n            return false;\n    }\n    else if (!_tcsicmp(extension, _T(\".url\")))\n    {\n        CString url = GetUrlFromUrlFile(lpszPathName);\n        return !url.IsEmpty() && openTopLevelUrl(url, false, lpszPathName); // sets m_reopenFunc\n    }\n    else\n    {\n        // https://community.spiceworks.com/topic/1968971-opening-web-links-downloading-1-item-to-zcrksihu\n        if (extension[0] == _T('\\0') && (_tcsstr(lpszPathName, _T(\"playlist\")) || _tcsstr(lpszPathName, _T(\"watch\")))\n            || !_tcsicmp(extension, _T(\".html\")) || !_tcsicmp(extension, _T(\".txt\")))\n        {\n            auto playList = ParsePlaylistFile(lpszPathName);\n            if (!playList.empty())\n            {\n                return openUrlFromList(playList);\n            }\n        }\n\n        CString mappedAudioFile;\n        if (openSeparateFile) {\n            if (!AfxGetApp()->m_pMainWnd && AfxGetMainWnd()) {\n                SetForegroundWindowInternal(*AfxGetMainWnd());\n                AfxGetMainWnd()->ShowWindow(SW_SHOW);\n            }\n            CFileDialog dlg(TRUE);\n            if (!currentDirectory.IsEmpty())\n                dlg.GetOFN().lpstrInitialDir = currentDirectory;\n            if (dlg.DoModal() != IDOK)\n            {\n                return false;\n            }\n            reset();\n            mappedAudioFile = dlg.GetPathName();\n            static_cast<CPlayerApp*>(AfxGetApp())->SetMappedAudioFile(lpszPathName, dlg.GetPathName());\n        }\n        else {\n            mappedAudioFile = static_cast<CPlayerApp*>(AfxGetApp())->GetMappedAudioFile(lpszPathName);\n        }\n\n        if (!mappedAudioFile.IsEmpty()) {\n            m_separateFileDiff = std::make_unique<StringDifference>(\n                lpszPathName, static_cast<LPCTSTR>(mappedAudioFile));\n        }\n        else if (m_autoPlay && m_separateFileDiff) {\n            const auto s = m_separateFileDiff->patch(lpszPathName);\n            if (!s.empty() && 0 != _tcscmp(s.c_str(), lpszPathName) && 0 == _taccess(s.c_str(), 04)) {\n                mappedAudioFile = s.c_str();\n            }\n            else {\n                m_separateFileDiff.reset();\n            }\n        }\n        else {\n            m_separateFileDiff.reset();\n        }\n\n        std::string pathNameA(CT2A(lpszPathName, CP_UTF8));\n        if (!mappedAudioFile.IsEmpty())\n        {\n            if (!m_frameDecoder->openUrls(\n                    {pathNameA, std::string(CT2A(mappedAudioFile, CP_UTF8))})) \n            {\n                return false;\n            }\n        }\n        else if (!m_frameDecoder->openUrls({pathNameA}))\n            return false;\n        m_playList.clear();\n\n        m_subtitles.reset();\n\n        if (m_autoPlay && m_subtitlesFileDiff) {\n            const auto s = m_subtitlesFileDiff->patch(lpszPathName);\n            auto map(std::make_unique<SubtitlesMap>());\n            if (!s.empty() && 0 != _tcscmp(s.c_str(), lpszPathName)\n                    && OpenSubtitlesFile(s.c_str(), map->m_unicodeSubtitles, GetAddToSubtitlesMapLambda(map))) {\n                m_subtitles = std::move(map);\n            }\n            else {\n                m_subtitlesFileDiff.reset();\n            }\n        }\n        else {\n            m_subtitlesFileDiff.reset();\n        }\n\n        if (!m_subtitles) {\n            auto map(std::make_unique<SubtitlesMap>());\n            if (OpenMatchingSubtitlesFile(lpszPathName, map->m_unicodeSubtitles, GetAddToSubtitlesMapLambda(map)))\n            {\n                m_subtitles = std::move(map);\n            }\n        }\n\n        m_frameDecoder->play();\n        onPauseResume(false);\n    }\n\n    m_reopenFunc = [this, path = CString(lpszPathName)] {\n        if (openDocument(path))\n            SetPathName(path, FALSE);\n    };\n    return true;\n}\n\nvoid CPlayerDoc::OnIdle()\n{\n    __super::OnIdle();\n\n    if (m_onEndOfStream)\n    {\n        m_onEndOfStream = false;\n        MoveToNextFile();\n    }\n\n    if (m_hConversionProcess != NULL && WaitForSingleObject(m_hConversionProcess, 0) == WAIT_OBJECT_0)\n    {\n        CloseHandle(m_hConversionProcess);\n        m_hConversionProcess = NULL;\n    }\n}\n\nvoid CPlayerDoc::OnFileSaveCopyAs()\n{\n    if (!DoSave(NULL, FALSE))\n        TRACE(\"Warning: File save-as failed.\\n\");\n}\n\nvoid CPlayerDoc::MoveToNextFile()\n{\n    auto saveReopenFunc = m_reopenFunc;\n\n    if (openUrlFromList() || m_autoPlay && HandleFilesSequence(\n        GetPathName(), \n        m_looping,\n        [this](const CString& path) \n        {\n            if (openDocument(path))\n            {\n                SetPathName(path, FALSE);\n                return true;\n            }\n            return false;\n        }))\n    {\n        m_reopenFunc = saveReopenFunc;\n        return;\n    }\n\n    if (m_playList.empty() && m_looping && m_reopenFunc)\n    {\n        // m_reopenFunc can be reset during invocation\n        auto tempReopenFunc = m_reopenFunc;\n        tempReopenFunc();\n    }\n}\n\nvoid CPlayerDoc::OnCloseDocument()\n{\n    m_frameDecoder->close();\n    m_subtitles.reset();\n    CDocument::OnCloseDocument();\n}\n\nvoid CPlayerDoc::SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU) \n{\n    if (_tcslen(lpszPathName) < _MAX_PATH)\n    {\n        __super::SetPathName(lpszPathName, bAddToMRU);\n        return;\n    }\n\n    m_strPathName = lpszPathName;\n\n    ASSERT(!m_strPathName.IsEmpty());  // must be set to something\n    m_bEmbedded = FALSE;\n\n    // set the document title based on path name\n    TCHAR szTitle[_MAX_FNAME];\n    if (::GetFileTitle(lpszPathName, szTitle, _countof(szTitle)) == 0)\n    {\n        SetTitle(szTitle);\n    }\n    else \n    {\n        SetTitle(::PathFindFileName(lpszPathName));\n    }\n\n    // add it to the file MRU list\n    //if (bAddToMRU)\n    //    AfxGetApp()->AddToRecentFileList(m_strPathName);\n}\n\n\nvoid CPlayerDoc::changedFramePosition(long long start, long long frame, long long total)\n{\n    framePositionChanged(frame - start, total - start);\n    const double currentTime = m_frameDecoder->getDurationSecs(frame);\n    m_currentTime = currentTime;\n    currentTimeUpdated(currentTime);\n\n    if (m_looping && !m_autoPlay && !isFullFrameRange() && m_currentTime >= m_rangeEndTime &&\n        m_endTime > m_startTime)\n    {\n        const double percent = (m_rangeStartTime - m_startTime) / (m_endTime - m_startTime);\n        m_frameDecoder->seekByPercent(percent);\n    }\n}\n\nvoid CPlayerDoc::decoderClosed(bool /*fileReleased*/)\n{\n    m_onEndOfStream = false;\n}\n\nvoid CPlayerDoc::fileLoaded(long long start, long long total)\n{\n    const double startTime = m_frameDecoder->getDurationSecs(start);\n    m_startTime = startTime;\n    startTimeUpdated(startTime);\n\n    const double endTime = m_frameDecoder->getDurationSecs(total);\n    m_endTime = endTime;\n    totalTimeUpdated(endTime);\n\n    setRangeStartTime(startTime);\n    setRangeEndTime(endTime);\n\n    if (CWnd* pMainWnd = AfxGetApp()->GetMainWnd())\n        pMainWnd->PostMessage(WM_KICKIDLE); // trigger idle update\n}\n\nvoid CPlayerDoc::onEndOfStream(int idx, bool error)\n{\n    if (idx != 0)\n        return;\n\n    if (!error && m_looping && !m_autoPlay && !isFullFrameRange() && m_endTime > m_startTime)\n    {\n        const double percent = (m_rangeStartTime - m_startTime) / (m_endTime - m_startTime);\n        if (m_frameDecoder->seekByPercent(percent))\n            return;\n    }\n\n    if (!m_onEndOfStream)\n    {\n        m_onEndOfStream = true;\n        if (CWnd* pMainWnd = AfxGetApp()->GetMainWnd())\n            pMainWnd->PostMessage(WM_KICKIDLE);  // trigger idle update\n    }\n}\n\nbool CPlayerDoc::pauseResume()\n{\n    if (m_frameDecoder->pauseResume())\n    {\n        onPauseResume(m_frameDecoder->isPaused());\n        return true;\n    }\n    return false;\n}\n\nbool CPlayerDoc::nextFrame()\n{\n    return m_frameDecoder->nextFrame();\n}\n\nbool CPlayerDoc::prevFrame()\n{\n    return m_frameDecoder->prevFrame();\n}\n\nbool CPlayerDoc::seekByPercent(double percent)\n{\n    return m_frameDecoder->seekByPercent(percent);\n}\n\nvoid CPlayerDoc::seekToEnd()\n{\n    if (m_autoPlay && m_currentTime - m_startTime > 5) // enable after 5 seconds\n    {\n        m_onEndOfStream = false;\n        MoveToNextFile();\n    }\n}\n\nvoid CPlayerDoc::setVolume(double volume)\n{\n    m_frameDecoder->setVolume(volume);\n}\n\nbool CPlayerDoc::isPlaying() const\n{\n    return m_frameDecoder->isPlaying();\n}\n\nbool CPlayerDoc::isPaused() const\n{\n    return m_frameDecoder->isPaused();\n}\n\ndouble CPlayerDoc::soundVolume() const\n{\n    return m_frameDecoder->volume();\n}\n\n\nstd::wstring CPlayerDoc::getSubtitle() const\n{\n    std::wstring result;\n    {\n        CSingleLock lock(&s_csSubtitles, TRUE);\n        if (m_subtitles)\n        {\n            auto it = m_subtitles->find(m_currentTime);\n            if (it != m_subtitles->end())\n            {\n                if (m_subtitles->m_unicodeSubtitles && m_bFixEncoding)\n                {\n                    CA2W bufW(it->second.c_str(), CP_UTF8);\n                    CW2A bufA(bufW, CP_ACP);\n                    result = CA2W(bufA, CP_UTF8);\n                }\n                else\n                {\n                    result = CA2W(it->second.c_str(),\n                                  m_subtitles->m_unicodeSubtitles ? CP_UTF8 : CP_ACP);\n                }\n            }\n        }\n    }\n\n    if (!result.empty())\n    {\n        using std::wregex;\n        // Replace any whitespace followed by a newline with an empty string\n        result = regex_replace(result, wregex(L\"\\\\s+(?=\\\\n)\"), L\"\");\n        // Replace punctuation followed by whitespace with the punctuation followed by a Unicode\n        // thin space character\n        result = regex_replace(result, wregex(L\"([,.?!;:])\\\\s\"), L\"$1\\u2009\");\n        // Replace an ellipsis occurring after a non-period character or at the start of the string\n        // with a Unicode ellipsis character\n        result = regex_replace(result, wregex(L\"(^|[^.])\\\\.{3}([^.]|$)\"), L\"$1\\u2026$2\");\n    }\n\n    return result;\n}\n\n\nvoid CPlayerDoc::setRangeStartTime(double time)\n{\n    if (time < min(0., m_startTime))\n        time = m_endTime + time;\n    m_rangeStartTime = time;\n    rangeStartTimeChanged(time - m_startTime, m_endTime - m_startTime);\n}\n\nvoid CPlayerDoc::setRangeEndTime(double time)\n{\n    if (time <= 0)\n        time = m_endTime + time;\n    m_rangeEndTime = time;\n    rangeEndTimeChanged(time - m_startTime, m_endTime - m_startTime);\n}\n\nvoid CPlayerDoc::setLosslessCut(bool flag)\n{\n    m_losslessCut = flag;\n}\n\nbool CPlayerDoc::isFullFrameRange() const\n{\n    return m_startTime == m_rangeStartTime && m_endTime == m_rangeEndTime;\n}\n\nvoid CPlayerDoc::OnAsyncUrl(const CString& url)\n{\n    if (!url.IsEmpty() && m_strPathName.IsEmpty() && m_url.empty())\n    {\n        openTopLevelUrl(url, false);\n    }\n}\n\nvoid CPlayerDoc::OnDropFiles(HDROP hDropInfo)\n{\n    const UINT cFiles = DragQueryFile(hDropInfo, (UINT)-1, NULL, 0);\n    if (cFiles == 0)\n        return;\n\n    if (cFiles == 1)\n    {\n        TCHAR lpszFileName[MAX_PATH];\n        if (DragQueryFile(hDropInfo, 0, lpszFileName, MAX_PATH)\n            && openDocument(lpszFileName))\n        {\n            SetPathName(lpszFileName, TRUE);\n        }\n    }\n    else\n    {\n        std::vector<std::string> playList;\n        for (UINT i = 0; i < cFiles; ++i)\n        {\n            TCHAR lpszFileName[MAX_PATH]{};\n            if (DragQueryFile(hDropInfo, i, lpszFileName, MAX_PATH))\n                playList.emplace_back(CT2A(lpszFileName, CP_UTF8));\n        }\n        if (!playList.empty())\n        {\n            GetDocTemplate()->SetDefaultTitle(this);\n            ClearPathName();\n            openUrlFromList(playList);\n        }\n    }\n}\n\nvoid CPlayerDoc::OnEditPaste(const std::string& text)\n{\n    auto playList = ParsePlaylistText(text);\n    if (!playList.empty())\n    {\n        GetDocTemplate()->SetDefaultTitle(this);\n        ClearPathName();\n        openUrlFromList(playList);\n    }\n}\n\nvoid CPlayerDoc::OnAudioTrack(UINT id)\n{\n    m_frameDecoder->setAudioTrack(id - ID_TRACK1);\n}\n\nvoid CPlayerDoc::OnUpdateAudioTrack(CCmdUI* pCmdUI)\n{\n    const int idx = pCmdUI->m_nID - ID_TRACK1;\n    pCmdUI->Enable(idx < m_frameDecoder->getNumAudioTracks());\n    pCmdUI->SetCheck(idx == m_frameDecoder->getAudioTrack());\n}\n\n\nvoid CPlayerDoc::OnAutoplay()\n{\n    m_autoPlay = !m_autoPlay;\n}\n\n\nvoid CPlayerDoc::OnUpdateAutoplay(CCmdUI *pCmdUI)\n{\n    pCmdUI->SetCheck(m_autoPlay);\n}\n\nvoid CPlayerDoc::OnLooping()\n{\n    m_looping = !m_looping;\n}\n\n\nvoid CPlayerDoc::OnUpdateLooping(CCmdUI *pCmdUI)\n{\n    pCmdUI->SetCheck(m_looping);\n}\n\nvoid CPlayerDoc::OnVideoSpeed(UINT id)\n{\n    const int idx = id - ID_VIDEO_SPEED1;\n    if (idx >= 0 && idx < sizeof(videoSpeeds) / sizeof(videoSpeeds[0]))\n    {\n        m_frameDecoder->setSpeedRational(videoSpeeds[idx]);\n        m_nightcore = (id == ID_NIGHTCORE);\n    }\n}\n\nvoid CPlayerDoc::OnUpdateVideoSpeed(CCmdUI* pCmdUI)\n{\n    const int idx = pCmdUI->m_nID - ID_VIDEO_SPEED1;\n    if (idx >= 0 && idx < sizeof(videoSpeeds) / sizeof(videoSpeeds[0]))\n    {\n        pCmdUI->Enable(m_frameDecoder->isPlaying());\n        pCmdUI->SetCheck((pCmdUI->m_nID == ID_NIGHTCORE) ? m_nightcore \n            : !m_nightcore && m_frameDecoder->getSpeedRational() == videoSpeeds[idx]);\n    }\n}\n\nfloat CPlayerDoc::getVideoSpeed() const\n{\n    if (m_nightcore)\n        return 1.f;\n    const auto speedRational = m_frameDecoder->getSpeedRational();\n    return static_cast<float>(speedRational.denominator) / speedRational.numerator;\n}\n\nCString CPlayerDoc::generateConversionScript() const\n{\n    const auto scriptTempPath = getScriptTempPath();\n\n    CHandle scriptFileHandle{ lockFile(scriptTempPath) };\n    if (!scriptFileHandle)\n    {\n        return {};\n    }\n\n    CFolderPickerDialog dlg;\n    if (IDOK != dlg.DoModal())\n    {\n        return {};\n    }\n\n    auto [isVideoCompatible, isAudioCompatible] = m_frameDecoder->isVideoAudioCompatible();\n    auto [width, height] =\n        m_frameDecoder->getVideoSize();  // make script decrease resolution if too high (larger than 1080p)\n    // Downscale only if resolution is above 1080p\n    const bool needsDownscale = (height > 1080 || width > 1920);\n    if (needsDownscale)\n    {\n        isVideoCompatible = false; // force conversion if downscaling is needed\n    }\n\n    // Build base message\n    CString msg = _T(\"Destination: \") + NoBreak(dlg.GetPathName()) +\n        _T(\"\\nOptions:\\n\") +\n        StrikeThrough(_T(\"Following,\"), !m_autoPlay) +\n        StrikeThrough(_T(\"Preceding,\"), !m_looping) +\n        StrikeThrough(_T(\"Separate Audio,\"), !m_separateFileDiff) +\n        StrikeThrough(_T(\"Separate Subtitles\"), !m_subtitlesFileDiff);\n\n    if (!isVideoCompatible)\n    {\n        // Mandatory conversion\n        msg += _T(\"\\n\\nThe video format is NOT compatible.\");\n        msg += _T(\"\\nConversion is required to proceed.\");\n        msg += _T(\"\\n\\nOK = Convert\\nCANCEL = Abort\");\n\n        UINT buttons = MB_OKCANCEL | MB_ICONWARNING;\n        auto r = AfxMessageBox(msg, buttons);\n\n        if (r != IDOK)\n        {\n            return {};\n        }\n\n        isVideoCompatible = false; // enforce conversion\n    }\n    else\n    {\n        // Optional conversion\n        msg += _T(\"\\n\\nThe video is compatible.\");\n        msg += _T(\"\\nYou may still convert it (e.g., to reduce size or ensure consistent encoding).\");\n        msg += _T(\"\\n\\nConvert the video?\");\n        msg += _T(\"\\nYES = Convert\\nNO = Keep original\\nCANCEL = Abort\");\n\n        UINT buttons = MB_YESNOCANCEL | MB_ICONQUESTION;\n        auto r = AfxMessageBox(msg, buttons);\n\n        if (r == IDCANCEL)\n        {\n            return {};\n        }\n\n        if (r == IDYES)\n            isVideoCompatible = false; // force conversion\n        else\n            isVideoCompatible = true;  // keep original\n    }\n\n    auto outputFolder = dlg.GetPathName();\n    ensureSeparator(outputFolder);\n\n    std::vector<CString> videoFiles;\n    if (m_autoPlay || m_looping)\n    {\n        if (!m_looping)\n        {\n            videoFiles.push_back(GetPathName());\n        }\n\n        HandleFilesSequence(\n            GetPathName(), m_autoPlay && m_looping,\n            [&videoFiles](const CString& path)\n            {\n                videoFiles.push_back(path);\n                return false;\n            },\n            m_looping);\n    }\n    else\n    {\n        videoFiles.push_back(GetPathName());\n    }\n\n\n    TCHAR pszAppFolderPath[MAX_PATH] = { 0 };\n    GetModuleFileName(NULL, pszAppFolderPath, ARRAYSIZE(pszAppFolderPath));\n    const auto pszAppFolderPathEnd = PathFindFileName(pszAppFolderPath);\n    *pszAppFolderPathEnd = 0;\n\n    CString ffmpegPath;\n    {\n        const TCHAR ffmpegExeName[] = _T(\"ffmpeg.exe\");\n        PathAppend(pszAppFolderPath, ffmpegExeName);\n        ffmpegPath = (_taccess(pszAppFolderPath, 04) == 0) \n            ? (_T('\"') + CString(pszAppFolderPath) + _T('\"')) : ffmpegExeName;\n        *pszAppFolderPathEnd = 0;\n    }\n\n    CString strText(_T(\"chcp 65001\\r\\n\"));\n\n    for (const auto& source : videoFiles)\n    {\n        CString command = ffmpegPath + _T(\" -i \\\"\") + source + _T('\"');\n\n        std::basic_string<TCHAR> separateFilePart;\n        if (m_separateFileDiff)\n        {\n            auto s = m_separateFileDiff->patch(\n                {source.GetString(), source.GetString() + source.GetLength()});\n            if (!s.empty())\n            {\n                separateFilePart = _T(\" -i \\\"\") + std::move(s) + _T('\"');\n            }\n        }\n        command += separateFilePart.c_str();\n\n        if (!isVideoCompatible)\n        {\n            CString vf;\n\n            if (needsDownscale)\n            {\n                // Proportional downscale to fit within 1080p, preserve aspect ratio\n                vf = _T(\"scale='min(1920,iw)':'min(1080,ih)':force_original_aspect_ratio=decrease,\")\n                    _T(\"pad=ceil(iw/2)*2:ceil(ih/2)*2\");\n            }\n            else\n            {\n                // Only pad to even dimensions\n                vf = _T(\"pad=ceil(iw/2)*2:ceil(ih/2)*2\");\n            }\n\n            command += _T(\" -vf \") + vf;\n        }\n\n        command += separateFilePart.empty() \n            ? _T(\" -map 0:v? -map 0:a?\") : _T(\" -map 0:v:0 -map 1:a:0\");\n        command += _T(\" -map 0:s?\");\n\n        command +=\n            isVideoCompatible ? _T(\" -c:v copy\") : _T(\" -c:v libx264 -crf 25 -pix_fmt yuv420p\");\n        command += (isAudioCompatible && !m_autoPlay && !m_looping) ? _T(\" -c:a copy\") : _T(\" -c:a aac -ac 2\");\n        command += _T(\" -c:s copy -preset superfast\");\n\n        if (m_separateFileDiff)\n        {\n            command += _T(\" -max_interleave_delta 0\");\n        }\n\n        command += _T(\" \\\"\");\n        command += outputFolder;\n        command += ::PathFindFileName(source);\n        command += _T(\"\\\"\\r\\n\");\n\n        strText += command;\n    }\n\n    if (m_subtitlesFileDiff)\n    {\n        PathAppend(pszAppFolderPath, _T(\"ToUTF8.exe\"));\n        CString subtitlesUtilPath = (_taccess(pszAppFolderPath, 04) == 0)\n            ? (_T('\"') + CString(pszAppFolderPath) + _T('\"')) : _T(\"copy\");\n        *pszAppFolderPathEnd = 0;\n\n        for (const auto& source : videoFiles)\n        {\n            const auto s = m_subtitlesFileDiff->patch(\n                {source.GetString(), source.GetString() + source.GetLength()});\n            if (s.empty())\n                continue;\n\n            const auto audioExt = ::PathFindExtension(s.c_str());\n\n            const auto fileNameWithExt = ::PathFindFileName(source);\n            std::basic_string<TCHAR> fileName{fileNameWithExt,\n                                              ::PathFindExtension(fileNameWithExt)};\n\n            auto command =\n                static_cast<LPCTSTR>(subtitlesUtilPath) + (_T(\" \\\"\") + s) + _T(\"\\\" \\\"\") \n                + static_cast<LPCTSTR>(outputFolder) + fileName + audioExt + _T(\"\\\"\\r\\n\");\n            strText += command.c_str();\n        }\n    }\n\n    CT2A bufA(strText, CP_UTF8);\n    writeFile(scriptFileHandle, bufA, strlen(bufA));\n\n    return scriptTempPath;\n}\n\n\nvoid CPlayerDoc::OnOpensubtitlesfile()\n{\n    CFileDialog dlg(TRUE); // TODO extensions\n    CString currentDirectory;\n    if (auto fileName = PathFindFileName(static_cast<LPCTSTR>(m_strPathName)))\n    {\n        currentDirectory = CString(static_cast<LPCTSTR>(m_strPathName),\n            fileName - static_cast<LPCTSTR>(m_strPathName));\n        dlg.GetOFN().lpstrInitialDir = currentDirectory;\n    }\n    if (dlg.DoModal() != IDOK)\n    {\n        return;\n    }\n\n    auto map(std::make_unique<SubtitlesMap>());\n    if (OpenSubtitlesFile(dlg.GetPathName(), map->m_unicodeSubtitles, GetAddToSubtitlesMapLambda(map)))\n    {\n        m_subtitlesFileDiff = std::make_unique<StringDifference>(\n            static_cast<LPCTSTR>(m_strPathName), static_cast<LPCTSTR>(dlg.GetPathName()));\n        CSingleLock lock(&s_csSubtitles, TRUE);\n        m_subtitles = std::move(map);\n    }\n}\n\n\nvoid CPlayerDoc::OnUpdateOpensubtitlesfile(CCmdUI *pCmdUI)\n{\n    pCmdUI->Enable(isPlaying() && m_url.empty());\n}\n\nvoid CPlayerDoc::OnCopyUrlToClipboard()\n{\n    const bool shiftAndControlPressed = GetKeyState(VK_SHIFT) < 0\n        && GetKeyState(VK_CONTROL) < 0;\n\n    const auto& url = shiftAndControlPressed ? m_url : m_originalUrl;\n\n    CString strText(url.empty() ? m_strPathName : CString(url.data(), url.length()));\n\n    CopyTextToClipboard(strText);\n}\n\n\nvoid CPlayerDoc::OnMaximalresolution()\n{\n    m_maximalResolution = !m_maximalResolution;\n}\n\n\nvoid CPlayerDoc::OnUpdateMaximalresolution(CCmdUI *pCmdUI)\n{\n    pCmdUI->SetCheck(m_maximalResolution);\n}\n\n\nvoid CPlayerDoc::OnHwAcceleration()\n{\n    m_frameDecoder->setHwAccelerated(!m_frameDecoder->getHwAccelerated());\n}\n\n\nvoid CPlayerDoc::OnUpdateHwAcceleration(CCmdUI *pCmdUI)\n{\n    pCmdUI->SetCheck(m_frameDecoder->getHwAccelerated());\n}\n\nvoid CPlayerDoc::OnGetSubtitles(UINT id)\n{\n    typedef std::pair<CPlayerDoc*, int> GetSubtitlesParams;\n\n    auto threadLam = [](LPVOID pParam) {\n        std::unique_ptr<GetSubtitlesParams> params(static_cast<GetSubtitlesParams*>(pParam));\n\n        auto map(std::make_shared<SubtitlesMap>());\n\n        map->m_unicodeSubtitles = true;\n\n        auto addToSubtitlesLam = [weakPtr = std::weak_ptr<SubtitlesMap>(map)](\n                double start, double end, const std::string& subtitle) {\n            if (auto map = weakPtr.lock()) {\n                CSingleLock lock(&s_csSubtitles, TRUE);\n                map->set({ boost::icl::interval<double>::closed(start, end), subtitle });\n                return true;\n            }\n            return false;\n        };\n\n        {\n            CSingleLock lock(&s_csSubtitles, TRUE);\n            params->first->m_subtitles = std::move(map);\n        }\n        params->first->m_frameDecoder->getSubtitles(params->second, addToSubtitlesLam);\n\n        return UINT();\n    };\n\n    AfxBeginThread(threadLam, new GetSubtitlesParams(this, id - ID_FIRST_SUBTITLE));\n}\n\n\nvoid CPlayerDoc::OnSuperResolution()\n{\n    m_superResolution = !m_superResolution;\n    if (m_superResolution)\n    {\n        CWaitCursor wait;\n        EnableImageUpscale();\n        m_frameDecoder->setImageConversionFunc(ImageUpscale);\n    }\n    else\n        m_frameDecoder->setImageConversionFunc({});\n}\n\n\nvoid CPlayerDoc::OnUpdateSuperResolution(CCmdUI *pCmdUI)\n{\n    pCmdUI->Enable(CanUpscaleImage());\n    pCmdUI->SetCheck(m_superResolution);\n}\n\n\nvoid CPlayerDoc::OnOrientationMirrorx()\n{\n    m_bOrientationMirrorx = !m_bOrientationMirrorx;\n    AfxGetApp()->GetMainWnd()->Invalidate();\n}\n\nvoid CPlayerDoc::OnUpdateOrientationMirrorx(CCmdUI *pCmdUI)\n{\n    pCmdUI->SetCheck(m_bOrientationMirrorx);\n}\n\n\nvoid CPlayerDoc::OnOrientationMirrory()\n{\n    m_bOrientationMirrory = !m_bOrientationMirrory;\n    AfxGetApp()->GetMainWnd()->Invalidate();\n}\n\n\nvoid CPlayerDoc::OnUpdateOrientationMirrory(CCmdUI *pCmdUI)\n{\n    pCmdUI->SetCheck(m_bOrientationMirrory);\n}\n\n\nvoid CPlayerDoc::OnOrientationUpend()\n{\n    m_bOrientationUpend = !m_bOrientationUpend;\n    AfxGetApp()->GetMainWnd()->Invalidate();\n}\n\n\nvoid CPlayerDoc::OnUpdateOrientationUpend(CCmdUI *pCmdUI)\n{\n    pCmdUI->SetCheck(m_bOrientationUpend);\n}\n\nvoid CPlayerDoc::OnOrientationDoNothing()\n{\n    m_bOrientationMirrorx = false;\n    m_bOrientationMirrory = false;\n    m_bOrientationUpend = false;\n    AfxGetApp()->GetMainWnd()->Invalidate();\n}\n\nvoid CPlayerDoc::OnOrientationRotate90()\n{\n    m_bOrientationMirrorx = false;\n    m_bOrientationMirrory = true;\n    m_bOrientationUpend = true;\n    AfxGetApp()->GetMainWnd()->Invalidate();\n}\n\nvoid CPlayerDoc::OnOrientationRotate180()\n{\n    m_bOrientationMirrorx = true;\n    m_bOrientationMirrory = true;\n    m_bOrientationUpend = false;\n    AfxGetApp()->GetMainWnd()->Invalidate();\n}\n\nvoid CPlayerDoc::OnOrientationRotate270()\n{\n    m_bOrientationMirrorx = true;\n    m_bOrientationMirrory = false;\n    m_bOrientationUpend = true;\n    AfxGetApp()->GetMainWnd()->Invalidate();\n}\n\nvoid CPlayerDoc::OnFixEncoding()\n{ \n    m_bFixEncoding = !m_bFixEncoding;\n}\n\nvoid CPlayerDoc::OnUpdateFixEncoding(CCmdUI* pCmdUI)\n{\n   pCmdUI->SetCheck(m_bFixEncoding); \n}\n\nvoid CPlayerDoc::OnConvertVideosIntoCompatibleFormat()\n{\n    if (m_hConversionProcess != NULL)\n    {\n        if (WaitForSingleObject(m_hConversionProcess, 0) == WAIT_OBJECT_0)\n        {\n            CloseHandle(m_hConversionProcess);\n            m_hConversionProcess = NULL;\n        }\n        else\n        {\n            return;\n        }\n    }\n\n\n    auto scriptTempPath = generateConversionScript();\n    if (scriptTempPath.IsEmpty())\n        return;\n\n    // Try to execute the file with the \"open\" verb\n    SHELLEXECUTEINFO ShExecInfo {};\n    ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO);\n    ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS;\n    ShExecInfo.hwnd = NULL;\n    ShExecInfo.lpVerb = _T(\"open\");\n    ShExecInfo.lpFile = scriptTempPath;\n    ShExecInfo.lpParameters = NULL;\n    ShExecInfo.lpDirectory = NULL;\n    ShExecInfo.nShow = SW_MINIMIZE;\n    ShExecInfo.hInstApp = NULL;\n    if (!ShellExecuteEx(&ShExecInfo))\n    {\n        TRACE(\"ShellExecuteEx failed with error code %d.\\n\", GetLastError());\n    }\n    else\n    {\n        m_hConversionProcess = ShExecInfo.hProcess;\n    }\n}\n\n\n\nvoid CPlayerDoc::OnUpdateConvertVideosIntoCompatibleFormat(CCmdUI* pCmdUI)\n{\n    if (GetPathName().IsEmpty() || !m_url.empty())\n    {\n        pCmdUI->Enable(false);\n        return;\n    }\n\n    const auto extension = PathFindExtension(GetPathName());\n    if (!_tcsicmp(extension, _T(\".lst\")) || !_tcsicmp(extension, _T(\".url\")))\n    {\n        pCmdUI->Enable(false);\n        return;\n    }\n\n    if (m_hConversionProcess != NULL)\n    {\n        if (WaitForSingleObject(m_hConversionProcess, 0) == WAIT_OBJECT_0)\n        {\n            CloseHandle(m_hConversionProcess);\n            m_hConversionProcess = NULL;\n        }\n        else\n        {\n            pCmdUI->Enable(false);\n            return;\n        }\n    }\n\n    const auto scriptTempPath = getScriptTempPath();\n    if (const auto scriptFileHandle = lockFile(scriptTempPath))\n    {\n        CloseHandle(scriptFileHandle);\n        pCmdUI->Enable(true);\n    }\n    else\n    {\n        pCmdUI->Enable(false);\n    }\n}\n\nvoid CPlayerDoc::OnOpenAudioFile()\n{\n    openDocument(GetPathName(), true);\n}\n\nvoid CPlayerDoc::OnUpdateOpenAudioFile(CCmdUI* pCmdUI)\n{\n    if (GetPathName().IsEmpty() || !m_url.empty())\n    {\n        pCmdUI->Enable(false);\n        return;\n    }\n\n    const auto extension = PathFindExtension(GetPathName());\n    if (!_tcsicmp(extension, _T(\".lst\")) || !_tcsicmp(extension, _T(\".url\")))\n    {\n        pCmdUI->Enable(false);\n        return;\n    }\n\n    pCmdUI->Enable(true);\n}\n\n\nvoid CPlayerDoc::OnUsingHostHeaderOverride()\n{\n    m_bUsingHHO = !m_bUsingHHO;\n}\n\n\nvoid CPlayerDoc::OnUpdateUsingHostHeaderOverride(CCmdUI* pCmdUI)\n{\n    pCmdUI->SetCheck(m_bUsingHHO);\n}\n\nvoid CPlayerDoc::OnVideoFilter()\n{\n    BOOL enableVideoFilter = FALSE;\n\n    {\n        CDialogVideoFilter dlg;\n        dlg.m_videoFilter = m_videoFilter;\n        dlg.m_enableVideoFilter = m_enableVideoFilter;\n        if (dlg.DoModal() != IDOK)\n            return;\n        dlg.m_videoFilter.Trim();  // in-place trim\n\n        if (m_videoFilter == dlg.m_videoFilter\n                && m_enableVideoFilter == dlg.m_enableVideoFilter)\n            return;\n\n        m_videoFilter = dlg.m_videoFilter;\n        enableVideoFilter = dlg.m_enableVideoFilter;\n    }\n\n    if (enableVideoFilter && !m_videoFilter.IsEmpty())\n    {\n        CW2A videoFilter(m_videoFilter, CP_UTF8);\n        FrameTransformer frameTransformer(static_cast<const char*>(videoFilter));\n        auto [width, height] = m_frameDecoder->getVideoSize();\n        auto ret = frameTransformer.init(width, height);\n        if (ret >= 0)\n        {\n            m_frameDecoder->setImageConversionFunc(frameTransformer);\n            m_enableVideoFilter = TRUE;\n            return;  // success\n        }\n        else\n        {\n            CString msg;\n            msg.Format(_T(\"Video filter setting failed. Error code: %d.\"), ret);\n            AfxMessageBox(msg);\n        }\n    }\n\n    // fallback to no filter\n    if (m_enableVideoFilter)\n    {\n        if (m_superResolution)\n            m_frameDecoder->setImageConversionFunc(ImageUpscale);\n        else\n            m_frameDecoder->setImageConversionFunc({});\n        m_enableVideoFilter = FALSE;\n    }\n}\n"
  },
  {
    "path": "Player/PlayerDoc.h",
    "content": "\n// PlayerDoc.h : interface of the CPlayerDoc class\n//\n\n#pragma once\n\n#pragma warning(disable:4996)\n\n#include <memory>\n#include <atomic>\n#include <deque>\n#include <string>\n#include <functional>\n\n#include <boost/signals2/signal.hpp>\n\n#include \"decoderinterface.h\"\n\nclass StringDifference;\n\nenum { UPDATE_HINT_CLOSING = 1 };\n\nclass CPlayerDoc : public CDocument, public FrameDecoderListener\n{\nprotected: // create from serialization only\n    CPlayerDoc();\n    DECLARE_DYNCREATE(CPlayerDoc)\n\n// Attributes\npublic:\n    IFrameDecoder* getFrameDecoder() const { return m_frameDecoder.get(); }\n\n// Operations\npublic:\n\n// Overrides\npublic:\n    BOOL OnNewDocument() override;\n    void Serialize(CArchive& ar) override;\n    void OnCloseDocument() override;\n    void SetPathName(LPCTSTR lpszPathName, BOOL bAddToMRU = TRUE) override;\n#ifdef SHARED_HANDLERS\n    virtual void InitializeSearchContent();\n    virtual void OnDrawThumbnail(CDC& dc, LPRECT lprcBounds);\n#endif // SHARED_HANDLERS\n\n// Implementation\npublic:\n    ~CPlayerDoc() override;\n#ifdef _DEBUG\n    void AssertValid() const override;\n    void Dump(CDumpContext& dc) const override;\n#endif\n\nprotected:\n    void changedFramePosition(long long start, long long frame, long long total) override;\n    void decoderClosed(bool fileReleased) override;\n    void fileLoaded(long long start, long long total) override;\n    void onEndOfStream(int idx, bool error) override;\n\n// Generated message map functions\nprotected:\n    afx_msg void OnAudioTrack(UINT id);\n    afx_msg void OnUpdateAudioTrack(CCmdUI* pCmdUI);\n    afx_msg void OnVideoSpeed(UINT id);\n    afx_msg void OnUpdateVideoSpeed(CCmdUI* pCmdUI);\n    afx_msg void OnAutoplay();\n    afx_msg void OnUpdateAutoplay(CCmdUI *pCmdUI);\n    afx_msg void OnLooping();\n    afx_msg void OnUpdateLooping(CCmdUI *pCmdUI);\n    afx_msg void OnOpensubtitlesfile();\n    afx_msg void OnUpdateOpensubtitlesfile(CCmdUI *pCmdUI);\n    afx_msg void OnCopyUrlToClipboard();\n    afx_msg void OnGetSubtitles(UINT id);\n    DECLARE_MESSAGE_MAP()\n\n#ifdef SHARED_HANDLERS\n    // Helper function that sets search content for a Search Handler\n    void SetSearchContent(const CString& value);\n#endif // SHARED_HANDLERS\npublic:\n    BOOL OnOpenDocument(LPCTSTR lpszPathName) override;\n\tBOOL DoFileSave() override { return FALSE; }\n    BOOL OnSaveDocument(LPCTSTR) override;\n    void OnIdle() override;\n    void OnFileSaveCopyAs();\n\n    bool pauseResume();\n    bool nextFrame();\n    bool prevFrame();\n    bool seekByPercent(double percent);\n    void seekToEnd();\n    void setVolume(double volume);\n\n    bool isPlaying() const;\n    bool isPaused() const;\n    double soundVolume() const;\n\n    boost::signals2::signal<void(long long, long long)> framePositionChanged;\n    boost::signals2::signal<void(double)> startTimeUpdated;\n    boost::signals2::signal<void(double)> totalTimeUpdated;\n    boost::signals2::signal<void(double)> currentTimeUpdated;\n\n    boost::signals2::signal<void(long long, long long)> rangeStartTimeChanged;\n    boost::signals2::signal<void(long long, long long)> rangeEndTimeChanged;\n\n    boost::signals2::signal<void(bool)> onPauseResume;\n\n    boost::signals2::signal<void()> onDestructing;\n\n    std::wstring getSubtitle() const;\n\n    void OnDropFiles(HDROP hDropInfo);\n    void OnEditPaste(const std::string& text);\n\n    double getCurrentTime() const { return m_currentTime; }\n\tdouble getStartTime() const { return m_startTime; }\n\tdouble getEndTime() const { return m_endTime; }\n\n    void setRangeStartTime(double time);\n    void setRangeEndTime(double time);\n\n    void setLosslessCut(bool flag);\n\n\tbool isFullFrameRange() const;\n\n    void OnAsyncUrl(const CString& url);\n\n    bool isOrientationMirrorx() const { return m_bOrientationMirrorx; }\n    bool isOrientationMirrory() const { return m_bOrientationMirrory; }\n    bool isOrientationUpend() const { return m_bOrientationUpend; }\n\nprivate:\n    void MoveToNextFile();\n\n    bool openDocument(LPCTSTR lpszPathName, bool openSeparateFile = false);\n    bool openTopLevelUrl(const CString& url, bool force, const CString& pathName = {});\n    bool openUrl(const std::string& url, const std::string& inputFormat = {});\n    bool openUrlFromList();\n    bool openUrlFromList(const std::vector<std::string>& playList, const CString& pathName = {});\n\n    void reset();\n\n    float getVideoSpeed() const;\n\n    CString generateConversionScript() const;\n\nprivate:\n    std::unique_ptr<IFrameDecoder> m_frameDecoder;\n\n    std::atomic<double> m_currentTime;\n    double m_startTime;\n    double m_endTime;\n\n    double m_rangeStartTime{};\n    double m_rangeEndTime{};\n\n    bool m_losslessCut = true;\n\n    class SubtitlesMap;\n    std::shared_ptr<SubtitlesMap> m_subtitles;\n    bool m_onEndOfStream = false;\n    bool m_autoPlay = false;\n    bool m_looping = false;\n\n    std::string m_originalUrl;\n    std::string m_url;\n\n    std::unique_ptr<StringDifference> m_separateFileDiff;\n    std::unique_ptr<StringDifference> m_subtitlesFileDiff;\n\n    std::deque<std::string> m_playList;\n    std::function<void()> m_reopenFunc;\n\n    bool m_nightcore = false;\n\n    unsigned int m_documentGeneration = 0;\n\n    bool m_maximalResolution = false;\n    bool m_superResolution = false;\n\n    bool m_bOrientationMirrorx = false;\n    bool m_bOrientationMirrory = false;\n    bool m_bOrientationUpend = false;\n\n    bool m_bFixEncoding = false;\n\n    bool m_bUsingHHO = true;\n\n    HANDLE m_hConversionProcess = NULL;\n\n    CString m_videoFilter;\n    BOOL m_enableVideoFilter = FALSE;\n\npublic:\n    afx_msg void OnMaximalresolution();\n    afx_msg void OnUpdateMaximalresolution(CCmdUI *pCmdUI);\n    afx_msg void OnHwAcceleration();\n    afx_msg void OnUpdateHwAcceleration(CCmdUI *pCmdUI);\n    afx_msg void OnSuperResolution();\n    afx_msg void OnUpdateSuperResolution(CCmdUI *pCmdUI);\n    afx_msg void OnOrientationMirrorx();\n    afx_msg void OnUpdateOrientationMirrorx(CCmdUI *pCmdUI);\n    afx_msg void OnOrientationMirrory();\n    afx_msg void OnUpdateOrientationMirrory(CCmdUI *pCmdUI);\n    afx_msg void OnOrientationUpend();\n    afx_msg void OnUpdateOrientationUpend(CCmdUI *pCmdUI);\n    afx_msg void OnOrientationDoNothing();\n    afx_msg void OnOrientationRotate90();\n    afx_msg void OnOrientationRotate180();\n    afx_msg void OnOrientationRotate270();\n    afx_msg void OnFixEncoding();\n    afx_msg void OnUpdateFixEncoding(CCmdUI* pCmdUI);\n    afx_msg void OnConvertVideosIntoCompatibleFormat();\n    afx_msg void OnUpdateConvertVideosIntoCompatibleFormat(CCmdUI* pCmdUI);\n    afx_msg void OnOpenAudioFile();\n    afx_msg void OnUpdateOpenAudioFile(CCmdUI* pCmdUI);\n    afx_msg void OnUsingHostHeaderOverride();\n    afx_msg void OnUpdateUsingHostHeaderOverride(CCmdUI* pCmdUI);\n    afx_msg void OnVideoFilter();\n};\n"
  },
  {
    "path": "Player/PlayerView.cpp",
    "content": "// PlayerViewDxva2.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n#include \"Player.h\"\n#include \"PlayerView.h\"\n#include \"PlayerDoc.h\"\n#include \"GetClipboardText.h\"\n#include \"FrameToHglobal.h\"\n\n#include \"decoderinterface.h\"\n\n//#include \"D3DFont.h\"\n\n#include <initguid.h>\n#include <d3d9.h>\n\n#ifdef USE_DXVA2\n#include <dxva2api.h>\n#endif\n\n#include <Gdiplus.h>\n\n#include <vector>\n\n#ifdef _DEBUG\n#define new DEBUG_NEW\n#endif\n\n#define CONVERT_FROM_YUV420P\n\nnamespace {\n\n#ifdef USE_DXVA2\nconst UINT VIDEO_REQUIED_OP = DXVA2_VideoProcess_YUV2RGB |\n                              DXVA2_VideoProcess_StretchX |\n                              DXVA2_VideoProcess_StretchY/* |\n                              DXVA2_VideoProcess_SubRects |\n                              DXVA2_VideoProcess_SubStreams*/;\n#endif\n\nconst D3DFORMAT VIDEO_RENDER_TARGET_FORMAT = D3DFMT_X8R8G8B8;\nconst D3DFORMAT VIDEO_MAIN_FORMAT = D3DFMT_YUY2;\nconst D3DFORMAT VIDEO_IMC3_FORMAT = (D3DFORMAT)MAKEFOURCC('I', 'M', 'C', '3');\n\nconst UINT BACK_BUFFER_COUNT = 1;\nconst UINT SUB_STREAM_COUNT = 0;\nconst UINT DWM_BUFFER_COUNT = 4;\n\nconst UINT VIDEO_FPS = 60;\n\n\nHMODULE g_hRgb9rastDLL = NULL;\n\nPVOID g_pfnD3D9GetSWInfo = nullptr;\n\n//////////////////////////////////////////////////////////////////////////////\n\nDWORD RGBtoYUV(const D3DCOLOR rgb)\n{\n    const INT A = HIBYTE(HIWORD(rgb));\n    const INT R = LOBYTE(HIWORD(rgb)) - 16;\n    const INT G = HIBYTE(LOWORD(rgb)) - 16;\n    const INT B = LOBYTE(LOWORD(rgb)) - 16;\n\n    //\n    // studio RGB [16...235] to SDTV ITU-R BT.601 YCbCr\n    //\n    INT Y = (77 * R + 150 * G + 29 * B + 128) / 256 + 16;\n    INT U = (-44 * R - 87 * G + 131 * B + 128) / 256 + 128;\n    INT V = (131 * R - 110 * G - 21 * B + 128) / 256 + 128;\n\n    return D3DCOLOR_AYUV(A, Y, U, V);\n}\n\nBOOL RegisterSoftwareRasterizer(IDirect3D9* g_pD3D9)\n{\n    if (!g_hRgb9rastDLL)\n    {\n        return FALSE;\n    }\n\n    HRESULT hr = g_pD3D9->RegisterSoftwareDevice(g_pfnD3D9GetSWInfo);\n\n    if (FAILED(hr))\n    {\n        TRACE(\"RegisterSoftwareDevice failed with error 0x%x.\\n\", hr);\n        return FALSE;\n    }\n\n    return TRUE;\n}\n\nBOOL InitializeModule()\n{\n    //\n    // Load these DLLs dynamically because these may not be available prior to Vista.\n    //\n    g_hRgb9rastDLL = LoadLibrary(TEXT(\"rgb9rast.dll\"));\n\n    if (!g_hRgb9rastDLL)\n    {\n        TRACE(\"LoadLibrary(rgb9rast.dll) failed with error %d.\\n\", GetLastError());\n    }\n    else\n    {\n        g_pfnD3D9GetSWInfo = GetProcAddress(g_hRgb9rastDLL, \"D3D9GetSWInfo\");\n\n        if (!g_pfnD3D9GetSWInfo)\n        {\n            TRACE(\"GetProcAddress(D3D9GetSWInfo) failed with error %d.\\n\", GetLastError());\n            return FALSE;\n        }\n    }\n\n    return TRUE;\n}\n\nD3DPRESENT_PARAMETERS GetD3dPresentParams(HWND hWnd)\n{\n    D3DPRESENT_PARAMETERS D3DPP = { 0 };\n\n    D3DPP.BackBufferWidth = GetSystemMetrics(SM_CXSCREEN);\n    D3DPP.BackBufferHeight = GetSystemMetrics(SM_CYSCREEN);\n\n    D3DPP.BackBufferFormat = VIDEO_RENDER_TARGET_FORMAT;\n    D3DPP.BackBufferCount = BACK_BUFFER_COUNT;\n    D3DPP.SwapEffect = D3DSWAPEFFECT_DISCARD;\n    D3DPP.hDeviceWindow = hWnd;\n    D3DPP.Windowed = TRUE;//g_bWindowed;\n    D3DPP.Flags = D3DPRESENTFLAG_VIDEO;\n    D3DPP.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;\n    D3DPP.PresentationInterval = D3DPRESENT_INTERVAL_ONE;\n\n    return D3DPP;\n}\n\n#ifdef USE_DXVA2\n\nDXVA2_VideoDesc GetVideoDesc(const CSize& sourceSize)\n{\n    DXVA2_VideoDesc videoDesc;\n\n    videoDesc.SampleWidth = sourceSize.cx;\n    videoDesc.SampleHeight = sourceSize.cy;\n    videoDesc.SampleFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_MPEG2;\n    videoDesc.SampleFormat.NominalRange = DXVA2_NominalRange_16_235;\n    videoDesc.SampleFormat.VideoTransferMatrix = DXVA2_VideoTransferMatrix_BT601;\n    videoDesc.SampleFormat.VideoLighting = DXVA2_VideoLighting_dim;\n    videoDesc.SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT709;\n    videoDesc.SampleFormat.VideoTransferFunction = DXVA2_VideoTransFunc_709;\n    videoDesc.SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame;\n    videoDesc.Format = VIDEO_MAIN_FORMAT;\n    videoDesc.InputSampleFreq.Numerator = VIDEO_FPS;\n    videoDesc.InputSampleFreq.Denominator = 1;\n    videoDesc.OutputFrameFreq.Numerator = VIDEO_FPS;\n    videoDesc.OutputFrameFreq.Denominator = 1;\n\n    return videoDesc;\n}\n\nDXVA2_AYUVSample16 GetBackgroundColor()\n{\n    const D3DCOLOR yuv = RGBtoYUV(0);\n\n    const BYTE Y = LOBYTE(HIWORD(yuv));\n    const BYTE U = HIBYTE(LOWORD(yuv));\n    const BYTE V = LOBYTE(LOWORD(yuv));\n\n    DXVA2_AYUVSample16 color;\n\n    color.Cr = V * 0x100;\n    color.Cb = U * 0x100;\n    color.Y = Y * 0x100;\n    color.Alpha = 0xFFFF;\n\n    return color;\n}\n\nconst LONGLONG start_100ns = 0;// frame * LONGLONG(VIDEO_100NSPF);\nconst LONGLONG end_100ns = 0;// start_100ns + LONGLONG(VIDEO_100NSPF);\n\nDXVA2_VideoProcessBltParams GetVideoProcessBltParams(\n    const CRect& target,\n    const LONG (&procAmpValues)[4],\n    const LONG (&nFilterValues)[6],\n    const LONG (&dFilterValues)[6])\n{\n    DXVA2_VideoProcessBltParams blt {};\n\n    // Initialize VPBlt parameters.\n    blt.TargetFrame = start_100ns;\n    blt.TargetRect = target;\n\n    // DXVA2_VideoProcess_Constriction\n    blt.ConstrictionSize.cx = target.Width();\n    blt.ConstrictionSize.cy = target.Height();\n\n    blt.BackgroundColor = GetBackgroundColor();\n\n    // DXVA2_VideoProcess_YUV2RGBExtended\n    blt.DestFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_Unknown;\n    blt.DestFormat.NominalRange = DXVA2_NominalRange_Unknown;\n    blt.DestFormat.VideoTransferMatrix = DXVA2_VideoTransferMatrix_Unknown;\n    blt.DestFormat.VideoLighting = DXVA2_VideoLighting_dim;\n    blt.DestFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT709;\n    blt.DestFormat.VideoTransferFunction = DXVA2_VideoTransFunc_709;\n\n    blt.DestFormat.SampleFormat = DXVA2_SampleProgressiveFrame;\n\n    // DXVA2_ProcAmp_Brightness\n    blt.ProcAmpValues.Brightness.ll = procAmpValues[0];\n    // DXVA2_ProcAmp_Contrast\n    blt.ProcAmpValues.Contrast.ll = procAmpValues[1];\n    // DXVA2_ProcAmp_Hue\n    blt.ProcAmpValues.Hue.ll = procAmpValues[2];\n    // DXVA2_ProcAmp_Saturation\n    blt.ProcAmpValues.Saturation.ll = procAmpValues[3];\n\n    // DXVA2_VideoProcess_AlphaBlend\n    blt.Alpha = DXVA2_Fixed32OpaqueAlpha();\n\n    // DXVA2_VideoProcess_NoiseFilter\n    blt.NoiseFilterLuma.Level.ll = nFilterValues[0];\n    blt.NoiseFilterLuma.Threshold.ll = nFilterValues[1];\n    blt.NoiseFilterLuma.Radius.ll = nFilterValues[2];\n    blt.NoiseFilterChroma.Level.ll = nFilterValues[3];\n    blt.NoiseFilterChroma.Threshold.ll = nFilterValues[4];\n    blt.NoiseFilterChroma.Radius.ll = nFilterValues[5];\n\n    // DXVA2_VideoProcess_DetailFilter\n    blt.DetailFilterLuma.Level.ll = dFilterValues[0];\n    blt.DetailFilterLuma.Threshold.ll = dFilterValues[1];\n    blt.DetailFilterLuma.Radius.ll = dFilterValues[2];\n    blt.DetailFilterChroma.Level.ll = dFilterValues[3];\n    blt.DetailFilterChroma.Threshold.ll = dFilterValues[4];\n    blt.DetailFilterChroma.Radius.ll = dFilterValues[5];\n\n    return blt;\n}\n\nDXVA2_VideoSample GetVideoSample(\n    const CSize& m_sourceSize,\n    const CRect& target,\n    IDirect3DSurface9* srcSurface)\n{\n    DXVA2_VideoSample sample {};\n\n    // Initialize main stream video sample.\n    sample.Start = start_100ns;\n    sample.End = end_100ns;\n\n    // DXVA2_VideoProcess_YUV2RGBExtended\n    sample.SampleFormat.VideoChromaSubsampling = DXVA2_VideoChromaSubsampling_MPEG2;\n    sample.SampleFormat.NominalRange = DXVA2_NominalRange_16_235;\n    sample.SampleFormat.VideoTransferMatrix = DXVA2_VideoTransferMatrix_BT601;\n    sample.SampleFormat.VideoLighting = DXVA2_VideoLighting_dim;\n    sample.SampleFormat.VideoPrimaries = DXVA2_VideoPrimaries_BT709;\n    sample.SampleFormat.VideoTransferFunction = DXVA2_VideoTransFunc_709;\n\n    sample.SampleFormat.SampleFormat = DXVA2_SampleProgressiveFrame;\n\n    sample.SrcSurface = srcSurface; //m_pMainStream;\n\n    // DXVA2_VideoProcess_SubRects\n    sample.SrcRect = { 0, 0, m_sourceSize.cx, m_sourceSize.cy };\n\n    // DXVA2_VideoProcess_StretchX, Y\n    sample.DstRect = target;\n\n    // DXVA2_VideoProcess_PlanarAlpha\n    sample.PlanarAlpha = DXVA2FloatToFixed(1.f);\n\n    return sample;\n}\n\n#endif\n\n\nvoid SimdCopyAndConvert(\n    __m128i* const __restrict origin0,\n    __m128i* const __restrict origin1,\n    const __m128i* const __restrict src00,\n    const __m128i* const __restrict src01,\n    const double* const __restrict src0,\n    const double* const __restrict src1,\n    size_t count)\n{\n    for (size_t i = 0; i < count; ++i)\n    {\n        __m128i uv = _mm_unpacklo_epi8(\n            _mm_castpd_si128(_mm_load_sd(src0 + i)),\n            _mm_castpd_si128(_mm_load_sd(src1 + i)));\n        _mm_stream_si128(origin0 + i * 2, _mm_unpacklo_epi8(src00[i], uv));\n        _mm_stream_si128(origin0 + i * 2 + 1, _mm_unpackhi_epi8(src00[i], uv));\n        _mm_stream_si128(origin1 + i * 2, _mm_unpacklo_epi8(src01[i], uv));\n        _mm_stream_si128(origin1 + i * 2 + 1, _mm_unpackhi_epi8(src01[i], uv));\n    }\n}\n\nvoid CopyAndConvert(\n    uint32_t* __restrict origin0,\n    uint32_t* __restrict origin1,\n    const uint8_t* __restrict src00,\n    const uint8_t* __restrict src01,\n    const uint8_t* __restrict src0,\n    const uint8_t* __restrict src1,\n    size_t count)\n{\n    if (!((intptr_t(origin0) & 15) || (intptr_t(origin1) & 15)\n        || (intptr_t(src00) & 15) || (intptr_t(src01) & 15)\n        || (intptr_t(src0) & 7) || (intptr_t(src1) & 7)))\n    {\n        const auto simdCount = count / 8;\n\n        SimdCopyAndConvert(\n            (__m128i*) origin0,\n            (__m128i*) origin1,\n            (const __m128i*) src00,\n            (const __m128i*) src01,\n            (const double*) src0,\n            (const double*) src1,\n            simdCount);\n\n        origin0 += simdCount * 8;\n        origin1 += simdCount * 8;\n        src00 += simdCount * 16;\n        src01 += simdCount * 16;\n        src0 += simdCount * 8;\n        src1 += simdCount * 8;\n\n        count -= simdCount * 8;\n    }\n\n    for (unsigned int j = 0; j < count; ++j)\n    {\n        const uint32_t uv = (src0[j] << 8) | (src1[j] << 24);\n        origin0[j] = uv | src00[j * 2] | (src00[j * 2 + 1] << 16);\n        origin1[j] = uv | src01[j * 2] | (src01[j * 2 + 1] << 16);\n    }\n}\n\nvoid CopyBuffer(uint8_t* dst, const uint8_t* src, size_t numBytes)\n{\n    if ((intptr_t(dst) & 15) || (intptr_t(src) & 15))\n    {\n        memcpy(dst, src, numBytes);\n        return;\n    }\n\n    size_t i = 0;\n    for (; i + 128 <= numBytes; i += 128)\n    {\n        __m128i d0 = _mm_load_si128((__m128i*)&src[i + 0 * 16]);\n        __m128i d1 = _mm_load_si128((__m128i*)&src[i + 1 * 16]);\n        __m128i d2 = _mm_load_si128((__m128i*)&src[i + 2 * 16]);\n        __m128i d3 = _mm_load_si128((__m128i*)&src[i + 3 * 16]);\n        __m128i d4 = _mm_load_si128((__m128i*)&src[i + 4 * 16]);\n        __m128i d5 = _mm_load_si128((__m128i*)&src[i + 5 * 16]);\n        __m128i d6 = _mm_load_si128((__m128i*)&src[i + 6 * 16]);\n        __m128i d7 = _mm_load_si128((__m128i*)&src[i + 7 * 16]);\n        _mm_stream_si128((__m128i*)&dst[i + 0 * 16], d0);\n        _mm_stream_si128((__m128i*)&dst[i + 1 * 16], d1);\n        _mm_stream_si128((__m128i*)&dst[i + 2 * 16], d2);\n        _mm_stream_si128((__m128i*)&dst[i + 3 * 16], d3);\n        _mm_stream_si128((__m128i*)&dst[i + 4 * 16], d4);\n        _mm_stream_si128((__m128i*)&dst[i + 5 * 16], d5);\n        _mm_stream_si128((__m128i*)&dst[i + 6 * 16], d6);\n        _mm_stream_si128((__m128i*)&dst[i + 7 * 16], d7);\n    }\n    for (; i + 16 <= numBytes; i += 16)\n    {\n        __m128i d = _mm_load_si128((__m128i*)&src[i]);\n        _mm_stream_si128((__m128i*)&dst[i], d);\n    }\n    for (; i + 4 <= numBytes; i += 4)\n    {\n        *(uint32_t*)&dst[i] = *(const uint32_t*)&src[i];\n    }\n    for (; i < numBytes; i++)\n    {\n        dst[i] = src[i];\n    }\n    //_mm_sfence();\n}\n\n// subtitles\n\nenum { MAX_NUM_VERTICES = 50 * 6 };\n\nstruct D3DXVECTOR4 {\n    FLOAT x;\n    FLOAT y;\n    FLOAT z;\n    FLOAT w;\n};\n\nstruct FONT2DVERTEX {\n    D3DXVECTOR4 p;\n    DWORD color;\n    FLOAT tu, tv;\n};\n\n\nCComPtr<IDirect3DStateBlock9> InitStateBlock(LPDIRECT3DDEVICE9 pd3dDevice,\n    IDirect3DTexture9* pTexture)\n{\n    pd3dDevice->BeginStateBlock();\n    pd3dDevice->SetTexture(0, pTexture);\n\n    //if (D3DFONT_ZENABLE & m_dwFontFlags)\n    //    pd3dDevice->SetRenderState(D3DRS_ZENABLE, TRUE);\n    //else\n    pd3dDevice->SetRenderState(D3DRS_ZENABLE, FALSE);\n\n    pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);\n    pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);\n    pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);\n    pd3dDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);\n    pd3dDevice->SetRenderState(D3DRS_ALPHAREF, 0x08);\n    pd3dDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL);\n    pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);\n    pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);\n    pd3dDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);\n    pd3dDevice->SetRenderState(D3DRS_CLIPPING, TRUE);\n    pd3dDevice->SetRenderState(D3DRS_CLIPPLANEENABLE, FALSE);\n    pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);\n    pd3dDevice->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);\n    pd3dDevice->SetRenderState(D3DRS_FOGENABLE, FALSE);\n    pd3dDevice->SetRenderState(D3DRS_COLORWRITEENABLE,\n        D3DCOLORWRITEENABLE_RED | D3DCOLORWRITEENABLE_GREEN |\n        D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_ALPHA);\n    pd3dDevice->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);\n    pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);\n    pd3dDevice->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);\n    pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);\n    pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);\n    pd3dDevice->SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);\n    pd3dDevice->SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0);\n    pd3dDevice->SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE);\n    pd3dDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);\n    pd3dDevice->SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);\n    pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);\n    pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);\n    pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);\n\n    CComPtr<IDirect3DStateBlock9> result;\n    pd3dDevice->EndStateBlock(&result);\n    return result;\n}\n\nvoid DrawSubtitleText(LPDIRECT3DDEVICE9 pd3dDevice, int width, int height, const std::wstring& text)\n{\n    using namespace Gdiplus;\n\n    const int fontSize = max(width / 60, 9);\n    auto font = std::make_unique<Gdiplus::Font>(L\"MS Sans Serif\", (REAL)fontSize);\n\n    RectF boundingBox;\n\n    {\n        Bitmap bitmap(1, 1);\n        Graphics graphics(&bitmap);\n        graphics.SetTextRenderingHint(TextRenderingHintSingleBitPerPixelGridFit);\n        graphics.MeasureString(text.c_str(), text.length(), font.get(), PointF(0, 0), &boundingBox);\n    }\n\n    if (boundingBox.Width > width)\n    {\n        font = std::make_unique<Gdiplus::Font>(L\"Arial Narrow\", (REAL)fontSize);\n        Bitmap bitmap(1, 1);\n        Graphics graphics(&bitmap);\n        graphics.SetTextRenderingHint(TextRenderingHintSingleBitPerPixelGridFit);\n        graphics.MeasureString(text.c_str(), text.length(), font.get(), PointF(0, 0), &boundingBox);\n    }\n\n    CComPtr<IDirect3DTexture9> pTexture;\n\n    // Create a new texture for the font\n    if (FAILED(pd3dDevice->CreateTexture(boundingBox.Width, boundingBox.Height, 1,\n        0,\n        D3DFMT_A4R4G4B4,\n        D3DPOOL_MANAGED, &pTexture, nullptr)))\n    {\n        return;\n    }\n\n    D3DLOCKED_RECT d3dlr;\n    if (FAILED(pTexture->LockRect(0, &d3dlr, nullptr, 0))) {\n        return;\n    }\n\n    {\n        Bitmap bitmap(boundingBox.Width, boundingBox.Height, d3dlr.Pitch,\n            PixelFormat16bppRGB565,\n            static_cast<BYTE*>(d3dlr.pBits));\n\n        Graphics graphics(&bitmap);\n        graphics.SetTextRenderingHint(TextRenderingHintSingleBitPerPixelGridFit);\n\n        SolidBrush whiteBrush(Color(0xFF, 0xFF, 0xFF));\n        graphics.DrawString(text.c_str(), text.length(), font.get(), PointF(0, 0), &whiteBrush);\n    }\n\n    pTexture->UnlockRect(0);\n\n    CComPtr<IDirect3DVertexBuffer9> pVB;\n    // Create vertex buffer for the letters\n    if (FAILED(pd3dDevice->CreateVertexBuffer(MAX_NUM_VERTICES * sizeof(FONT2DVERTEX),\n        D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,\n        D3DPOOL_DEFAULT, &pVB, nullptr)))\n    {\n        return;\n    }\n\n    CComPtr<IDirect3DStateBlock9> pStateBlockSaved(InitStateBlock(pd3dDevice, pTexture));\n    if (!pStateBlockSaved) {\n        return;\n    }\n\n    CComPtr<IDirect3DStateBlock9> pStateBlockDrawText(InitStateBlock(pd3dDevice, pTexture));\n    if (!pStateBlockDrawText) {\n        return;\n    }\n\n    // Setup renderstate\n    pStateBlockSaved->Capture();\n    pStateBlockDrawText->Apply();\n    pd3dDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);\n    pd3dDevice->SetPixelShader(nullptr);\n    pd3dDevice->SetStreamSource(0, pVB, 0, sizeof(FONT2DVERTEX));\n\n    const FLOAT tx1 = 0;\n    const FLOAT ty1 = 0;\n    const FLOAT tx2 = 1;\n    const FLOAT ty2 = 1;\n\n    const FLOAT w = boundingBox.Width;\n    const FLOAT h = boundingBox.Height;\n\n    // Fill vertex buffer\n    FONT2DVERTEX* pVertices = nullptr;\n    DWORD         dwNumTriangles = 0;\n    if (FAILED(pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD))) {\n        return;\n    }\n\n    for (int pass = 0; pass < 2; ++pass)\n    {\n        const FLOAT sx = (width - boundingBox.Width + 1) / 2 + !pass;\n        const FLOAT sy = height - boundingBox.Height - fontSize / 3 + !pass;\n\n        const DWORD dwColor = pass? D3DCOLOR_XRGB(255, 255, 255) : D3DCOLOR_XRGB(0, 0, 0);\n\n        *pVertices++ = { { sx + 0, sy + h, 0.9F, 1.0F }, dwColor, tx1, ty2 };\n        *pVertices++ = { { sx + 0, sy + 0, 0.9F, 1.0F }, dwColor, tx1, ty1 };\n        *pVertices++ = { { sx + w, sy + h, 0.9F, 1.0F }, dwColor, tx2, ty2 };\n        *pVertices++ = { { sx + w, sy + 0, 0.9F, 1.0F }, dwColor, tx2, ty1 };\n        *pVertices++ = { { sx + w, sy + h, 0.9F, 1.0F }, dwColor, tx2, ty2 };\n        *pVertices++ = { { sx + 0, sy + 0, 0.9F, 1.0F }, dwColor, tx1, ty1 };\n\n        dwNumTriangles += 2;\n    }\n\n    // Unlock and render the vertex buffer\n    pVB->Unlock();\n    if (dwNumTriangles > 0) {\n        pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles);\n    }\n\n    // Restore the modified renderstates\n    pStateBlockSaved->Apply();\n}\n\nbool Transform(LPDIRECT3DDEVICE9 m_pD3DD9, IDirect3DSurface9* m_pMainStream,\n               const CSize& m_sourceSize, int w, int h, bool mirrorX, bool mirrorY, bool upend)\n{\n    CComPtr<IDirect3DTexture9> pTexture;\n\n    // Create a new texture for the stuff\n    if (FAILED(m_pD3DD9->CreateTexture(m_sourceSize.cx & ~1, m_sourceSize.cy & ~1,\n        1, D3DUSAGE_RENDERTARGET,\n        VIDEO_RENDER_TARGET_FORMAT, D3DPOOL_DEFAULT, &pTexture, nullptr)))\n    {\n        return false;\n    }\n\n    CComPtr<IDirect3DSurface9> dest;\n\n    if (FAILED(pTexture->GetSurfaceLevel(0, &dest)))\n    {\n        return false;\n    }\n\n    RECT srcRect = {0, 0, m_sourceSize.cx & ~1, m_sourceSize.cy & ~1};\n\n    if (FAILED(m_pD3DD9->StretchRect(m_pMainStream,\n                                     &srcRect,\n                                     dest,\n                                     NULL,\n                                     D3DTEXF_LINEAR)))\n    {\n        return false;\n    }\n\n    CComPtr<IDirect3DVertexBuffer9> pVB;\n    // Create vertex buffer for the stuff\n    if (FAILED(m_pD3DD9->CreateVertexBuffer(MAX_NUM_VERTICES * sizeof(FONT2DVERTEX),\n                                            D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC, 0,\n                                            D3DPOOL_DEFAULT, &pVB, nullptr)))\n    {\n        return false;\n    }\n\n    // capture/apply?\n    CComPtr<IDirect3DStateBlock9> pStateBlockSaved(InitStateBlock(m_pD3DD9, pTexture));\n    if (!pStateBlockSaved)\n    {\n        return false;\n    }\n\n    CComPtr<IDirect3DStateBlock9> pStateBlockDrawText(InitStateBlock(m_pD3DD9, pTexture));\n    if (!pStateBlockDrawText)\n    {\n        return false;\n    }\n\n    // Setup renderstate\n    pStateBlockSaved->Capture();\n    pStateBlockDrawText->Apply();\n\n    m_pD3DD9->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1);\n    m_pD3DD9->SetPixelShader(nullptr);\n    m_pD3DD9->SetStreamSource(0, pVB, 0, sizeof(FONT2DVERTEX));\n\n    const FLOAT tx1 = mirrorX;\n    const FLOAT tx2 = !mirrorX;\n    const FLOAT ty1 = mirrorY;\n    const FLOAT ty2 = !mirrorY;\n\n    // Fill vertex buffer\n    FONT2DVERTEX* pVertices = nullptr;\n    if (FAILED(pVB->Lock(0, 0, (void**)&pVertices, D3DLOCK_DISCARD)))\n    {\n        return false;\n    }\n\n    const FLOAT sx = 0;\n    const FLOAT sy = 0;\n\n    const DWORD dwColor = D3DCOLOR_XRGB(255, 255, 255);\n\n    *pVertices++ = {{sx + 0, sy + h, 0.9F, 1.0F}, dwColor, upend ? tx2 : tx1, upend ? ty1 : ty2};\n    *pVertices++ = {{sx + 0, sy + 0, 0.9F, 1.0F}, dwColor, tx1, ty1};\n    *pVertices++ = {{sx + w, sy + h, 0.9F, 1.0F}, dwColor, tx2, ty2};\n    *pVertices++ = {{sx + w, sy + 0, 0.9F, 1.0F}, dwColor, upend ? tx1 : tx2, upend ? ty2 : ty1};\n    *pVertices++ = {{sx + w, sy + h, 0.9F, 1.0F}, dwColor, tx2, ty2};\n    *pVertices++ = {{sx + 0, sy + 0, 0.9F, 1.0F}, dwColor, tx1, ty1};\n\n    const UINT dwNumTriangles = 2;\n\n    // Unlock and render the vertex buffer\n    pVB->Unlock();\n    if (FAILED(m_pD3DD9->DrawPrimitive(D3DPT_TRIANGLELIST, 0, dwNumTriangles)))\n    {\n        return false;\n    }\n    // Restore the modified renderstates\n    pStateBlockSaved->Apply();\n\n    return true;\n}\n\n} // namespace\n\n\nclass FrameListener : public IFrameListener\n{\npublic:\n    explicit FrameListener(CPlayerView* playerView) : m_playerView(playerView) {}\n\nprivate:\n    void updateFrame(IFrameDecoder* decoder, unsigned int generation) override\n    {\n        m_playerView->updateFrame();\n        decoder->finishedDisplayingFrame(generation);\n    }\n    void drawFrame(IFrameDecoder* /*decoder*/, unsigned int /*generation*/) override\n    {\n        m_playerView->ProcessVideo();\n        //m_playerView->Invalidate();\n        //decoder->finishedDisplayingFrame(generation);\n    }\n    void decoderClosing() override\n    {\n        if (!m_playerView->m_pD3D9)\n        {\n            m_playerView->DestroyExtra();\n            m_playerView->DestroyD3D9();\n        }\n    }\n\nprivate:\n    CPlayerView* m_playerView;\n};\n\n// CPlayerView\n\nIMPLEMENT_DYNCREATE(CPlayerView, CView)\n\nCPlayerView::CPlayerView()\n    : m_frameListener(new FrameListener(this))\n    , m_aspectRatio(1, 1)\n{\n}\n\nCPlayerView::~CPlayerView()\n{\n    GetDocument()->getFrameDecoder()->setFrameListener(nullptr);\n}\n\nBEGIN_MESSAGE_MAP(CPlayerView, CView)\n    ON_COMMAND(ID_EDIT_PASTE, &CPlayerView::OnEditPaste)\n    ON_WM_PAINT()\n    ON_WM_CREATE()\n    ON_WM_ERASEBKGND()\n    ON_WM_DROPFILES()\n    ON_COMMAND(ID_EDIT_COPY, &CPlayerView::OnEditCopy)\nEND_MESSAGE_MAP()\n\n\n\nbool CPlayerView::InitializeD3D9()\n{\n    m_pD3D9.Attach(Direct3DCreate9(D3D_SDK_VERSION));\n\n    if (!m_pD3D9)\n    {\n        TRACE(\"Direct3DCreate9 failed.\\n\");\n        return false;\n    }\n\n    auto D3DPP = GetD3dPresentParams(*this);\n\n    //\n    // First try to create a hardware D3D9 device.\n    //\n    HRESULT hr = m_pD3D9->CreateDevice(D3DADAPTER_DEFAULT,\n        D3DDEVTYPE_HAL,\n        m_hWnd,\n        D3DCREATE_FPU_PRESERVE |\n        D3DCREATE_MULTITHREADED |\n        D3DCREATE_HARDWARE_VERTEXPROCESSING,\n        &D3DPP,\n        &m_pD3DD9);\n\n    if (FAILED(hr))\n    {\n        TRACE(\"CreateDevice(HAL) failed with error 0x%x.\\n\", hr);\n    }\n\n    if (!m_pD3DD9)\n    {\n        hr = m_pD3D9->CreateDevice(D3DADAPTER_DEFAULT,\n            D3DDEVTYPE_HAL,\n            m_hWnd,\n            D3DCREATE_FPU_PRESERVE |\n            D3DCREATE_MULTITHREADED |\n            D3DCREATE_SOFTWARE_VERTEXPROCESSING,\n            &D3DPP,\n            &m_pD3DD9);\n\n        if (FAILED(hr))\n        {\n            TRACE(\"CreateDevice(HAL+SOFTWARE_VERTEXPROCESSING) failed with error 0x%x.\\n\", hr);\n        }\n    }\n\n    //\n    // Next try to create a software D3D9 device.\n    //\n    if (!m_pD3DD9)\n    {\n        RegisterSoftwareRasterizer(m_pD3D9);\n\n        hr = m_pD3D9->CreateDevice(D3DADAPTER_DEFAULT,\n            D3DDEVTYPE_SW,\n            m_hWnd,\n            D3DCREATE_FPU_PRESERVE |\n            D3DCREATE_MULTITHREADED |\n            D3DCREATE_SOFTWARE_VERTEXPROCESSING,\n            &D3DPP,\n            &m_pD3DD9);\n\n        if (FAILED(hr))\n        {\n            TRACE(\"CreateDevice(SW) failed with error 0x%x.\\n\", hr);\n        }\n    }\n\n    return !!m_pD3DD9;\n}\n\n#ifdef USE_DXVA2\nbool CPlayerView::CreateDXVA2VPDevice(REFGUID guid, bool bDXVA2SW, bool createSurface)\n{\n    //\n    // Query the supported render target format.\n    //\n    UINT i, count;\n    D3DFORMAT* formats = NULL;\n\n    auto videoDesc = GetVideoDesc(m_sourceSize);\n\n    HRESULT hr = m_pDXVAVPS->GetVideoProcessorRenderTargets(guid,\n        &videoDesc,\n        &count,\n        &formats);\n\n    if (FAILED(hr))\n    {\n        TRACE(\"GetVideoProcessorRenderTargets failed with error 0x%x.\\n\", hr);\n        return false;\n    }\n\n    for (i = 0; i < count; ++i)\n    {\n        if (formats[i] == VIDEO_RENDER_TARGET_FORMAT)\n        {\n            break;\n        }\n    }\n\n    CoTaskMemFree(formats);\n\n    if (i >= count)\n    {\n        TRACE(\"GetVideoProcessorRenderTargets doesn't support that format.\\n\");\n        return false;\n    }\n\n    DXVA2_VideoProcessorCaps g_VPCaps = { 0 };\n\n    //\n    // Query video processor capabilities.\n    //\n    hr = m_pDXVAVPS->GetVideoProcessorCaps(guid,\n        &videoDesc,\n        VIDEO_RENDER_TARGET_FORMAT,\n        &g_VPCaps);\n\n    if (FAILED(hr))\n    {\n        TRACE(\"GetVideoProcessorCaps failed with error 0x%x.\\n\", hr);\n        return false;\n    }\n\n\n    //\n    // Check to see if the device is software device.\n    //\n    if (g_VPCaps.DeviceCaps & DXVA2_VPDev_SoftwareDevice)\n    {\n        if (!bDXVA2SW)\n        {\n            TRACE(\"The DXVA2 device isn't a hardware device.\\n\");\n            return false;\n        }\n    }\n    else\n    {\n        if (bDXVA2SW)\n        {\n            TRACE(\"The DXVA2 device isn't a software device.\\n\");\n            return false;\n        }\n    }\n\n    //\n    // This is a progressive device and we cannot provide any reference sample.\n    //\n    if (g_VPCaps.NumForwardRefSamples > 0 || g_VPCaps.NumBackwardRefSamples > 0)\n    {\n        TRACE(\"NumForwardRefSamples or NumBackwardRefSamples is greater than 0.\\n\");\n        return false;\n    }\n\n    //\n    // Check to see if the device supports all the VP operations we want.\n    //\n    if ((g_VPCaps.VideoProcessorOperations & VIDEO_REQUIED_OP) != VIDEO_REQUIED_OP)\n    {\n        TRACE(\"The DXVA2 device doesn't support the VP operations.\\n\");\n        return false;\n    }\n\n    //\n    // Create a main stream surface.\n    //\n    if (createSurface)\n    {\n        hr = m_pDXVAVPS->CreateSurface(\n            (m_sourceSize.cx + 7) & ~7,\n            m_sourceSize.cy,\n            0,\n            VIDEO_MAIN_FORMAT,\n            g_VPCaps.InputPool,\n            0,\n            DXVA2_VideoSoftwareRenderTarget,\n            &m_pMainStream,\n            NULL);\n\n        if (FAILED(hr))\n        {\n            TRACE(\"CreateSurface(MainStream) failed with error 0x%x.\\n\", hr);\n            return false;\n        }\n    }\n\n    //\n    // Query ProcAmp ranges.\n    //\n    DXVA2_ValueRange range;\n\n    for (i = 0; i < ARRAYSIZE(m_ProcAmpValues); ++i)\n    {\n        if (g_VPCaps.ProcAmpControlCaps & (1 << i))\n        {\n            hr = m_pDXVAVPS->GetProcAmpRange(guid,\n                &videoDesc,\n                VIDEO_RENDER_TARGET_FORMAT,\n                1 << i,\n                &range);\n\n            if (FAILED(hr))\n            {\n                TRACE(\"GetProcAmpRange failed with error 0x%x.\\n\", hr);\n                return false;\n            }\n\n            m_ProcAmpValues[i] = range.DefaultValue.ll;\n        }\n    }\n\n    //\n    // Query Noise Filter ranges.\n    //\n    if (g_VPCaps.VideoProcessorOperations & DXVA2_VideoProcess_NoiseFilter)\n    {\n        for (i = 0; i < ARRAYSIZE(m_NFilterValues); ++i)\n        {\n            hr = m_pDXVAVPS->GetFilterPropertyRange(guid,\n                &videoDesc,\n                VIDEO_RENDER_TARGET_FORMAT,\n                DXVA2_NoiseFilterLumaLevel + i,\n                &range);\n\n            if (FAILED(hr))\n            {\n                TRACE(\"GetFilterPropertyRange(Noise) failed with error 0x%x.\\n\", hr);\n                return false;\n            }\n\n            m_NFilterValues[i] = range.DefaultValue.ll;\n        }\n    }\n\n    //\n    // Query Detail Filter ranges.\n    //\n    if (g_VPCaps.VideoProcessorOperations & DXVA2_VideoProcess_DetailFilter)\n    {\n        for (i = 0; i < ARRAYSIZE(m_DFilterValues); ++i)\n        {\n            hr = m_pDXVAVPS->GetFilterPropertyRange(guid,\n                &videoDesc,\n                VIDEO_RENDER_TARGET_FORMAT,\n                DXVA2_DetailFilterLumaLevel + i,\n                &range);\n\n            if (FAILED(hr))\n            {\n                TRACE(\"GetFilterPropertyRange(Detail) failed with error 0x%x.\\n\", hr);\n                return false;\n            }\n\n            m_DFilterValues[i] = range.DefaultValue.ll;\n        }\n    }\n\n    //\n    // Finally create a video processor device.\n    //\n    hr = m_pDXVAVPS->CreateVideoProcessor(guid,\n        &videoDesc,\n        VIDEO_RENDER_TARGET_FORMAT,\n        SUB_STREAM_COUNT,\n        &m_pDXVAVPD);\n\n    if (FAILED(hr))\n    {\n        TRACE(\"CreateVideoProcessor failed with error 0x%x.\\n\", hr);\n        return false;\n    }\n\n    return true;\n}\n#endif\n\nbool CPlayerView::InitializeExtra(bool createSurface)\n{\n    m_bUseIMC3 = false;\n\n    HRESULT hr = S_OK;\n\n#ifdef USE_DXVA2\n    // Create DXVA2 Video Processor Service.\n    hr = DXVA2CreateVideoService(m_pD3DD9,\n        IID_IDirectXVideoProcessorService,\n        (VOID**)&m_pDXVAVPS);\n\n    if (FAILED(hr))\n    {\n        TRACE(\"DXVA2CreateVideoService failed with error 0x%x.\\n\", hr);\n        return false;\n    }\n\n    // Initialize the video descriptor.\n\n    // Query the video processor GUID.\n    UINT count;\n    GUID* guids = NULL;\n\n    auto videoDesc = GetVideoDesc(m_sourceSize);\n    hr = m_pDXVAVPS->GetVideoProcessorDeviceGuids(&videoDesc, &count, &guids);\n\n    if (FAILED(hr))\n    {\n        TRACE(\"GetVideoProcessorDeviceGuids failed with error 0x%x.\\n\", hr);\n        return false;\n    }\n\n    // Create a DXVA2 device.\n    bool created = false;\n    for (UINT i = 0; i < count; ++i)\n    {\n        if (CreateDXVA2VPDevice(guids[i], false, createSurface))\n        {\n            created = true;\n            break;\n        }\n    }\n    if (!created)\n    {\n        for (UINT i = 0; i < count; ++i)\n        {\n            if (CreateDXVA2VPDevice(guids[i], true, createSurface))\n            {\n                created = true;\n                break;\n            }\n        }\n    }\n\n    CoTaskMemFree(guids);\n\n    if (!m_pDXVAVPD)\n    {\n        TRACE(\"Failed to create a DXVA2 device.\\n\");\n        return false;\n    }\n#else\n    if (createSurface)\n    {\n#ifdef CONVERT_FROM_YUV420P\n        hr = m_pD3DD9->CreateOffscreenPlainSurface(\n            (m_sourceSize.cx + 7) & ~7,\n            (m_sourceSize.cy + 31) & ~31,\n            VIDEO_IMC3_FORMAT,\n            D3DPOOL_DEFAULT,\n            &m_pMainStream,\n            nullptr);\n        if (SUCCEEDED(hr))\n        {\n            m_bUseIMC3 = true;\n        }\n        else\n#endif\n        {\n            hr = m_pD3DD9->CreateOffscreenPlainSurface(\n                (m_sourceSize.cx + 7) & ~7,\n                m_sourceSize.cy,\n                VIDEO_MAIN_FORMAT,\n                D3DPOOL_DEFAULT,\n                &m_pMainStream,\n                nullptr);\n            if (FAILED(hr))\n            {\n                TRACE(\"CreateOffscreenPlainSurface failed with error 0x%x.\\n\", hr);\n                return false;\n            }\n        }\n    }\n#endif\n\n    // Retrieve a back buffer as the video render target.\n    hr = m_pD3DD9->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &m_pD3DRT);\n\n    if (FAILED(hr))\n    {\n        TRACE(\"GetBackBuffer failed with error 0x%x.\\n\", hr);\n        return false;\n    }\n\n    //m_subtitleFont = std::make_unique<CD3DFont>(\n    //    _T(\"MS Sans Serif\"),\n    //    max(m_sourceSize.cx / 50, 9));\n    //m_subtitleFont->InitDeviceObjects(m_pD3DD9);\n    //m_subtitleFont->RestoreDeviceObjects();\n    return true;\n}\n\nvoid CPlayerView::DestroyExtra()\n{\n    //if (m_subtitleFont)\n    //{\n    //    m_subtitleFont->InvalidateDeviceObjects();\n    //    m_subtitleFont->DeleteDeviceObjects();\n    //    m_subtitleFont.reset();\n    //}\n\n    m_pMainStream.Release();\n#ifdef USE_DXVA2\n    m_pDXVAVPD.Release();\n    m_pDXVAVPS.Release();\n#endif\n    m_pD3DRT.Release();\n}\n\nvoid CPlayerView::DestroyD3D9()\n{\n    m_pD3DD9.Release();\n    m_pD3D9.Release();\n}\n\n\nbool CPlayerView::ResetDevice()\n{\n    bool fullInitialization = true;\n\n    if (m_pD3DD9)\n    {\n        //\n        // Destroy DXVA2 device because it may be holding any D3D9 resources.\n        //\n        DestroyExtra();\n\n        //\n        // Reset will change the parameters, so use a copy instead.\n        //\n        auto d3dpp = GetD3dPresentParams(*this);\n\n        HRESULT hr = m_pD3DD9->Reset(&d3dpp);\n\n        if (FAILED(hr))\n        {\n            TRACE(\"Reset failed with error 0x%x.\\n\", hr);\n        }\n\n        if (SUCCEEDED(hr) && InitializeExtra(true))\n        {\n            fullInitialization = false;\n        }\n        else\n        {\n            //\n            // If either Reset didn't work or failed to initialize DXVA2 device,\n            // try to recover by recreating the devices from the scratch.\n            //\n            DestroyExtra();\n            DestroyD3D9();\n        }\n    }\n\n    return !(fullInitialization && (!InitializeD3D9() || !InitializeExtra(true)));\n}\n\n\nCRect CPlayerView::GetScreenPosition(bool swapXY)\n{\n    CRect desc;\n    GetClientRect(&desc);\n\n    long long aspectFrameX(m_sourceSize.cx * m_aspectRatio.cx);\n    long long aspectFrameY(m_sourceSize.cy * m_aspectRatio.cy);\n    if (swapXY)\n    {\n        std::swap(aspectFrameX, aspectFrameY);\n    }\n\n    CRect target;\n    if (aspectFrameY * desc.Width() > aspectFrameX * desc.Height())\n    {\n        target.top = 0;\n        target.bottom = desc.Height();\n        LONG width = LONG(aspectFrameX * desc.Height() / aspectFrameY);\n        LONG offset = (desc.Width() - width) / 2;\n        target.left = offset;\n        target.right = width + offset;\n    }\n    else\n    {\n        target.left = 0;\n        target.right = desc.Width();\n        LONG height = LONG(aspectFrameY * desc.Width() / aspectFrameX);\n        LONG offset = (desc.Height() - height) / 2;\n        target.top = offset;\n        target.bottom = height + offset;\n    }\n\n    return target;\n}\n\n\n// CPlayerView drawing\n\nbool CPlayerView::ProcessVideo()\n{\n    if (!m_pD3DD9)\n    {\n        return false;\n    }\n\n    CSingleLock lock(&m_csSurface, TRUE);\n\n    // Check the current status of D3D9 device.\n    HRESULT hr = m_pD3DD9->TestCooperativeLevel();\n    switch (hr)\n    {\n    case D3D_OK:\n        break;\n\n    case D3DERR_DEVICELOST:\n        TRACE(\"TestCooperativeLevel returned D3DERR_DEVICELOST.\\n\");\n        return true;\n\n    case D3DERR_DEVICENOTRESET:\n        TRACE(\"TestCooperativeLevel returned D3DERR_DEVICENOTRESET.\\n\");\n\n        if (!m_pD3D9)\n        {\n            DestroyExtra();\n            DestroyD3D9();\n            GetDocument()->getFrameDecoder()->videoReset();\n            return false;\n        }\n        if (!ResetDevice())\n        {\n            return false;\n        }\n\n        break;\n\n    default:\n        TRACE(\"TestCooperativeLevel failed with error 0x%x.\\n\", hr);\n        return false;\n    }\n\n    RECT srcRect = {0, 0, m_sourceSize.cx & ~1, m_sourceSize.cy & ~1};\n    CRect screenPosition = GetScreenPosition(GetDocument()->isOrientationUpend());\n    CRect target(POINT{}, screenPosition.Size());\n\n\n#ifdef USE_DXVA2\n    const auto blt = GetVideoProcessBltParams(\n        target,\n        m_ProcAmpValues,\n        m_NFilterValues,\n        m_DFilterValues);\n    const auto sample = GetVideoSample(m_sourceSize, target, m_pMainStream);\n\n    hr = m_pDXVAVPD->VideoProcessBlt(m_pD3DRT,\n        &blt,\n        &sample,\n        SUB_STREAM_COUNT + 1,\n        NULL);\n    if (FAILED(hr))\n    {\n        TRACE(\"VideoProcessBlt failed with error 0x%x.\\n\", hr);\n    }\n#else\n    m_pD3DD9->Clear(\n        0,\n        nullptr,\n        D3DCLEAR_TARGET,\n        D3DCOLOR_XRGB(0, 0, 0),\n        1.0F,\n        0);\n\n    if (!GetDocument()->isOrientationMirrorx() \n        && !GetDocument()->isOrientationMirrory() \n        && !GetDocument()->isOrientationUpend())\n    {\n        hr = m_pD3DD9->StretchRect(\n            m_pMainStream,\n            &srcRect,\n            m_pD3DRT,\n            &target,\n            D3DTEXF_NONE);\n        if (FAILED(hr))\n        {\n            TRACE(\"StretchRect failed with error 0x%x.\\n\", hr);\n        }\n    }\n    else\n    {\n        hr = m_pD3DD9->BeginScene();\n        if (SUCCEEDED(hr))\n        {\n            Transform(m_pD3DD9, m_pMainStream,\n                m_sourceSize, screenPosition.Width(), screenPosition.Height(),\n                GetDocument()->isOrientationMirrorx(),\n                GetDocument()->isOrientationMirrory(),\n                GetDocument()->isOrientationUpend());\n\n            m_pD3DD9->EndScene();\n        }\n    }\n#endif\n\n    if (auto subtitle = GetDocument()->getSubtitle(); !subtitle.empty())\n    {\n        //const auto& convertedSubtitle = CA2T(subtitle.c_str(), CP_UTF8);\n        hr = m_pD3DD9->BeginScene();\n        if (SUCCEEDED(hr))\n        {\n            //CSize boundingBox;\n            //m_subtitleFont->GetTextExtent(convertedSubtitle, &boundingBox);\n            //const CSize frameSize = target.Size();\n            //const auto left = (frameSize.cx - boundingBox.cx) / 2;\n            //const auto top = frameSize.cy - boundingBox.cy - 2;\n            //m_subtitleFont->DrawText(left + 1, top + 1, D3DCOLOR_XRGB(0, 0, 0), convertedSubtitle);\n            //m_subtitleFont->DrawText(left, top, D3DCOLOR_XRGB(255, 255, 255), convertedSubtitle);\n\n            DrawSubtitleText(m_pD3DD9, target.Width(), target.Height(), subtitle);\n\n            m_pD3DD9->EndScene();\n        }\n    }\n\n\n    hr = m_pD3DD9->Present(&target, &screenPosition, GetSafeHwnd(), nullptr);\n    if (FAILED(hr))\n    {\n        TRACE(\"Present failed with error 0x%x.\\n\", hr);\n    }\n\n    return true;\n}\n\n\nvoid CPlayerView::OnDraw(CDC* /*pDC*/)\n{\n    //CDocument* pDoc = GetDocument();\n    // TODO: add draw code here\n}\n\nvoid CPlayerView::OnEditPaste()\n{\n    const auto text = GetClipboardText();\n    if (!text.empty())\n    {\n        GetDocument()->OnEditPaste(text);\n    }\n}\n\n// CPlayerView diagnostics\n\n#ifdef _DEBUG\nvoid CPlayerView::AssertValid() const\n{\n    CView::AssertValid();\n}\n\n#ifndef _WIN32_WCE\nvoid CPlayerView::Dump(CDumpContext& dc) const\n{\n    CView::Dump(dc);\n}\n#endif\n#endif //_DEBUG\n\nCPlayerDoc* CPlayerView::GetDocument() const\n{\n    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPlayerDoc)));\n    return static_cast<CPlayerDoc*>(m_pDocument);\n}\n\n\n// CPlayerView message handlers\n\n\nvoid CPlayerView::OnPaint()\n{\n    if (!m_pD3DD9)\n    {\n        __super::OnPaint();\n    }\n    else\n    {\n        ProcessVideo();\n        ValidateRect(nullptr);\n    }\n}\n\n\nBOOL CPlayerView::PreCreateWindow(CREATESTRUCT& cs)\n{\n    // For the full screen mode\n    cs.style &= ~WS_BORDER;\n    cs.dwExStyle &= ~WS_EX_CLIENTEDGE;\n\n    return CView::PreCreateWindow(cs);\n}\n\n\nint CPlayerView::OnCreate(LPCREATESTRUCT lpCreateStruct)\n{\n    if (!InitializeModule()) {\n        return -1;\n    }\n\n    if (CView::OnCreate(lpCreateStruct) == -1) {\n        return -1;\n    }\n\n    GetDocument()->getFrameDecoder()->setFrameListener(m_frameListener.get());\n    GetDocument()->getFrameDecoder()->SetFrameFormat(IFrameDecoder::\n#ifdef CONVERT_FROM_YUV420P\n        PIX_FMT_YUV420P\n#else\n        PIX_FMT_YUYV422\n#endif\n        , true);\n\n    DragAcceptFiles();\n\n    return 0;\n}\n\nvoid CPlayerView::updateFrame()\n{\n    CSingleLock lock(&m_csSurface, TRUE);\n\n    FrameRenderingData data;\n    if (!GetDocument()->getFrameDecoder()->getFrameRenderingData(&data))\n    {\n        return;\n    }\n\n    data.width &= -2; // must be even\n\n    m_aspectRatio.cx = data.aspectNum;\n    m_aspectRatio.cy = data.aspectDen;\n\n    if (data.d3d9device)\n    {\n        if (data.d3d9device != m_pD3DD9)\n        {\n            m_sourceSize.cx = data.width;\n            m_sourceSize.cy = data.height;\n\n            DestroyExtra();\n            DestroyD3D9();\n\n            m_pD3DD9 = data.d3d9device;\n            m_pD3D9.Release();\n\n            InitializeExtra(false);\n        }\n    }\n    else if (!m_pD3D9 || data.width != m_sourceSize.cx || data.height != m_sourceSize.cy)\n    {\n        m_sourceSize.cx = data.width;\n        m_sourceSize.cy = data.height;\n        ResetDevice();\n    }\n\n    if (data.surface)\n    {\n        m_pMainStream = data.surface;\n    }\n    else\n    {\n        if (!m_pMainStream)\n        {\n            TRACE(\"m_pMainStream is NULL!\\n\");\n            return;\n        }\n        D3DLOCKED_RECT lr;\n        HRESULT hr = m_pMainStream->LockRect(&lr, nullptr, D3DLOCK_NOSYSLOCK);\n        if (FAILED(hr))\n        {\n            TRACE(\"LockRect failed with error 0x%x.\\n\", hr);\n            return;\n        }\n\n#ifdef CONVERT_FROM_YUV420P\n        if (m_bUseIMC3)\n        {\n            const int normalizedHeight = (data.height + 31) & ~31;\n\n            uint8_t* const pU = (uint8_t*)lr.pBits + (normalizedHeight * lr.Pitch);\n            uint8_t* const pV = (uint8_t*)lr.pBits + (((normalizedHeight * 3) / 2) * lr.Pitch);\n            \n            uint8_t* const planes[] { (uint8_t*)lr.pBits, pU, pV };\n            \n            int width = data.width;\n            int height = data.height;\n            for (int plane = 0; plane < 3; ++plane)\n            {\n                auto bits = planes[plane];\n                for (int i = 0; i < height; ++i)\n                {\n                    CopyBuffer(bits + lr.Pitch * i, data.image[plane] + data.pitch[plane] * i,\n                               width);\n                }\n                width = data.width / 2;\n                height = data.height / 2;\n            }\n        }\n        else\n        {\n            for (int i = 0; i < data.height / 2; ++i)\n            {\n                CopyAndConvert(\n                    (uint32_t*)((char*)lr.pBits + lr.Pitch * 2 * i),\n                    (uint32_t*)((char*)lr.pBits + lr.Pitch * (2 * i + 1)),\n                    data.image[0] + data.pitch[0] * 2 * i,\n                    data.image[0] + data.pitch[0] * (2 * i + 1),\n                    data.image[1] + data.pitch[1] * i,\n                    data.image[2] + data.pitch[2] * i,\n                    data.width / 2);\n            }\n        }\n#else\n        const size_t lineSize = (size_t)min(lr.Pitch, data.width * 2);\n        for (int i = 0; i < data.height; ++i)\n        {\n            memcpy((BYTE*)lr.pBits + lr.Pitch * i, data.image[0] + data.width * 2 * i, lineSize);\n        }\n#endif\n\n        hr = m_pMainStream->UnlockRect();\n        if (FAILED(hr))\n        {\n            TRACE(\"UnlockRect failed with error 0x%x.\\n\", hr);\n        }\n    }\n\n    lock.Unlock();\n\n    if (auto* pMainWnd = dynamic_cast<CFrameWndEx*>(AfxGetApp()->GetMainWnd())) {\n        if (pMainWnd->IsFullScreen())\n        {\n            ::SetThreadExecutionState(ES_DISPLAY_REQUIRED | ES_SYSTEM_REQUIRED | ES_CONTINUOUS);\n        }\n    }\n}\n\n\nBOOL CPlayerView::OnEraseBkgnd(CDC* pDC)\n{\n    if (!m_pD3DD9)\n    {\n        // Save old brush\n        CGdiObject* pOldBrush = pDC->SelectStockObject(BLACK_BRUSH);\n\n        CRect rect;\n        pDC->GetClipBox(&rect);     // Erase the area needed\n\n        pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),\n            PATCOPY);\n        pDC->SelectObject(pOldBrush);\n    }\n    return TRUE;\n}\n\nvoid CPlayerView::OnErase(CWnd* pInitiator, CDC* pDC, BOOL isFullScreen)\n{\n    if (!!m_pD3DD9)\n    {\n        CSingleLock lock(&m_csSurface, TRUE);\n\n        CRect rect;\n        if (isFullScreen)\n        {\n            pDC->GetClipBox(&rect);     // Erase the area needed\n        }\n        else\n        {\n            GetClientRect(&rect);\n            MapWindowPoints(pInitiator, &rect);\n        }\n        CRect targetRect = GetScreenPosition(GetDocument()->isOrientationUpend());\n        targetRect.DeflateRect(1, 1);\n        MapWindowPoints(pInitiator, &targetRect);\n\n        CRgn clientRgn;\n        VERIFY(clientRgn.CreateRectRgnIndirect(&rect));\n        CRgn targetRgn;\n        VERIFY(targetRgn.CreateRectRgnIndirect(&targetRect));\n        CRgn combined;\n        VERIFY(combined.CreateRectRgnIndirect(&rect));\n        VERIFY(combined.CombineRgn(&clientRgn, &targetRgn, RGN_DIFF) != ERROR);\n\n        // Save old brush\n        CGdiObject* pOldBrush = pDC->SelectStockObject(BLACK_BRUSH);\n        pDC->PaintRgn(&combined);\n        pDC->SelectObject(pOldBrush);\n    }\n}\n\n\nvoid CPlayerView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)\n{\n    if (lHint == UPDATE_HINT_CLOSING)\n    {\n        {\n            CSingleLock lock(&m_csSurface, TRUE);\n            DestroyExtra();\n            DestroyD3D9();\n            m_sourceSize = {};\n        }\n        RedrawWindow();\n    }\n\n    __super::OnUpdate(pSender, lHint, pHint);\n}\n\n\nvoid CPlayerView::OnDropFiles(HDROP hDropInfo)\n{\n    GetDocument()->OnDropFiles(hDropInfo);\n    __super::OnDropFiles(hDropInfo);\n}\n\n\nvoid CPlayerView::OnEditCopy()\n{\n    if (!m_pMainStream) {\n        return;\n    }\n\n    if (!OpenClipboard()) {\n        return;\n    }\n\n    const int allocatedHeight = m_bUseIMC3 ? ((m_sourceSize.cy + 31) & ~31) : m_sourceSize.cy;\n    if (HGLOBAL hglbl = FrameToHglobal(m_pMainStream, m_sourceSize.cx, m_sourceSize.cy, allocatedHeight))\n    {\n        EmptyClipboard();\n        SetClipboardData(CF_DIB, hglbl);\n    }\n    CloseClipboard();\n}\n"
  },
  {
    "path": "Player/PlayerView.h",
    "content": "#pragma once\n\n#include \"IEraseableArea.h\"\n\n#include <memory>\n\nstruct IFrameListener;\n\nstruct IDirect3D9;\nstruct IDirect3DDevice9;\nstruct IDirect3DSurface9;\nstruct IDirectXVideoProcessorService;\nstruct IDirectXVideoProcessor;\n\n//class CD3DFont;\n\nclass CPlayerDoc;\n\n//#define USE_DXVA2\n\n// CPlayerView view\n\nclass CPlayerView : public CView, public IEraseableArea\n{\n    friend class FrameListener;\n\n    DECLARE_DYNCREATE(CPlayerView)\n\nprotected:\n    CPlayerView();           // protected constructor used by dynamic creation\n    virtual ~CPlayerView();\n\npublic:\n    virtual void OnDraw(CDC* pDC);      // overridden to draw this view\n#ifdef _DEBUG\n    virtual void AssertValid() const;\n#ifndef _WIN32_WCE\n    virtual void Dump(CDumpContext& dc) const;\n#endif\n#endif\n\n    CPlayerDoc* GetDocument() const;\n\n    void updateFrame();\n\n    void OnErase(CWnd* pInitiator, CDC* pDC, BOOL isFullScreen) override;\n\nprotected:\n    DECLARE_MESSAGE_MAP()\nprivate:\n    bool InitializeD3D9();\n    bool InitializeExtra(bool createSurface);\n    void DestroyExtra();\n    void DestroyD3D9();\n#ifdef USE_DXVA2\n    bool CreateDXVA2VPDevice(REFGUID guid, bool bDXVA2SW, bool createSurface);\n#endif\n    bool ResetDevice();\n    bool ProcessVideo();\n\n    CRect GetScreenPosition(bool swapXY);\n\nprivate:\n    std::unique_ptr<IFrameListener> m_frameListener;\n    CSize m_sourceSize;\n    CSize m_aspectRatio;\n\n    CCriticalSection m_csSurface;\n\n    CComPtr<IDirect3D9> m_pD3D9;\n    CComPtr<IDirect3DDevice9>  m_pD3DD9;\n    CComPtr<IDirect3DSurface9> m_pD3DRT;\n    CComPtr<IDirect3DSurface9> m_pMainStream;\n\n    bool m_bUseIMC3 = false;\n\n#ifdef USE_DXVA2\n    CComPtr<IDirectXVideoProcessorService> m_pDXVAVPS;\n    CComPtr<IDirectXVideoProcessor> m_pDXVAVPD;\n\n    LONG m_ProcAmpValues[4] {};\n    LONG m_NFilterValues[6] {};\n    LONG m_DFilterValues[6] {};\n#endif\n\n    //std::unique_ptr<CD3DFont> m_subtitleFont;\n\npublic:\n    afx_msg void OnPaint();\n    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);\n    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);\n    afx_msg BOOL OnEraseBkgnd(CDC* pDC);\n    virtual void OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/);\n    afx_msg void OnDropFiles(HDROP hDropInfo);\n    afx_msg void OnEditPaste();\n    afx_msg void OnEditCopy();\n};\n"
  },
  {
    "path": "Player/PlayerViewD2D.cpp",
    "content": "\n#include \"stdafx.h\"\n// SHARED_HANDLERS can be defined in an ATL project implementing preview, thumbnail\n// and search filter handlers and allows sharing of document code with that project.\n#ifndef SHARED_HANDLERS\n#include \"Player.h\"\n#endif\n\n#include \"PlayerDoc.h\"\n#include \"PlayerViewD2D.h\"\n\n#include \"I420Effect.h\"\n\n#include \"GetClipboardText.h\"\n\n#include \"decoderinterface.h\"\n\n#include <d2d1_2.h>\n\n\n#ifdef _DEBUG\n#define new DEBUG_NEW\n#endif\n\nenum { WM_DRAW_FRAME = WM_USER + 101 };\n\nnamespace {\n\n//Use IDWriteTextLayout to get the text size\nHRESULT GetTextSize(const std::wstring& text, IDWriteTextFormat* pTextFormat, const SIZE& sourceSize, D2D1_SIZE_F& size)\n{\n    CComPtr<IDWriteTextLayout> pTextLayout;\n    // Create a text layout\n    auto len = text.length();\n    if (len > 0 && text[len - 1] == L'\\n')\n        --len;\n    auto hr = AfxGetD2DState()->GetWriteFactory()->CreateTextLayout(\n        text.c_str(),\n        len,\n        pTextFormat, \n        sourceSize.cx, \n        sourceSize.cy, \n        &pTextLayout);\n    if (SUCCEEDED(hr))\n    {\n        //Gets the text size\n        DWRITE_TEXT_METRICS textMetrics;\n        hr = pTextLayout->GetMetrics(&textMetrics);\n        size = D2D1::SizeF(textMetrics.width, textMetrics.height);\n    }\n    return hr;\n}\n\n} // namespace\n\nclass FrameListenerD2D : public IFrameListener\n{\npublic:\n    explicit FrameListenerD2D(CPlayerViewD2D* playerView) : m_playerView(playerView) {}\n\nprivate:\n    void updateFrame(IFrameDecoder* decoder, unsigned int generation) override\n    {\n        m_playerView->updateFrame();\n        decoder->finishedDisplayingFrame(generation, IFrameDecoder::RELEASE_FRAME);\n    }\n    void drawFrame(IFrameDecoder*, unsigned int generation) override\n    {\n        m_playerView->SendNotifyMessage(WM_DRAW_FRAME, 0, generation);\n    }\n    void decoderClosing() override\n    {\n    }\n\nprivate:\n    CPlayerViewD2D* m_playerView;\n};\n\n\n// CPlayerViewD2D\n\nIMPLEMENT_DYNCREATE(CPlayerViewD2D, CView)\n\nBEGIN_MESSAGE_MAP(CPlayerViewD2D, CView)\n    // Standard printing commands\n    ON_COMMAND(ID_EDIT_PASTE, &CPlayerViewD2D::OnEditPaste)\n    ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)\n    ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)\n    ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)\n    ON_REGISTERED_MESSAGE(AFX_WM_DRAW2D, &CPlayerViewD2D::OnDraw2D)\n    ON_MESSAGE(WM_DRAW_FRAME, &CPlayerViewD2D::DrawFrame)\n    ON_WM_CREATE()\n    ON_WM_DROPFILES()\nEND_MESSAGE_MAP()\n\n// CPlayerViewD2D construction/destruction\n\nCPlayerViewD2D::CPlayerViewD2D()\n    : m_frameListener(new FrameListenerD2D(this))\n    , m_aspectRatio(1.f)\n{\n    // Enable D2D support for this window:\n    EnableD2DSupport();\n}\n\nCPlayerViewD2D::~CPlayerViewD2D()\n{\n    GetDocument()->getFrameDecoder()->setFrameListener(nullptr);\n}\n\nBOOL CPlayerViewD2D::PreCreateWindow(CREATESTRUCT& cs)\n{\n    // For the full screen mode\n    cs.style &= ~WS_BORDER;\n    cs.dwExStyle &= ~WS_EX_CLIENTEDGE;\n\n    return CView::PreCreateWindow(cs);\n}\n\nvoid CPlayerViewD2D::OnEditPaste()\n{\n    const auto text = GetClipboardText();\n    if (!text.empty())\n    {\n        GetDocument()->OnEditPaste(text);\n    }\n}\n\n// CPlayerViewD2D drawing\n\nvoid CPlayerViewD2D::OnDraw(CDC* /*pDC*/)\n{\n    CPlayerDoc* pDoc = GetDocument();\n    ASSERT_VALID(pDoc);\n    if (!pDoc)\n        return;\n\n    // TODO: add draw code for native data here\n}\n\n\n// CPlayerViewD2D printing\n\nBOOL CPlayerViewD2D::OnPreparePrinting(CPrintInfo* pInfo)\n{\n    // default preparation\n    return DoPreparePrinting(pInfo);\n}\n\nvoid CPlayerViewD2D::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)\n{\n    // TODO: add extra initialization before printing\n}\n\nvoid CPlayerViewD2D::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)\n{\n    // TODO: add cleanup after printing\n}\n\n\n// CPlayerViewD2D diagnostics\n\n#ifdef _DEBUG\nvoid CPlayerViewD2D::AssertValid() const\n{\n    CView::AssertValid();\n}\n\nvoid CPlayerViewD2D::Dump(CDumpContext& dc) const\n{\n    CView::Dump(dc);\n}\n#endif //_DEBUG\n\nCPlayerDoc* CPlayerViewD2D::GetDocument() const\n{\n    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPlayerDoc)));\n    return static_cast<CPlayerDoc*>(m_pDocument);\n}\n\n\n// CPlayerViewD2D message handlers\n\nafx_msg LRESULT CPlayerViewD2D::OnDraw2D(WPARAM, LPARAM lParam)\n{\n    CHwndRenderTarget* pRenderTarget = (CHwndRenderTarget*)lParam;\n    ASSERT_VALID(pRenderTarget);\n\n    CRect rect;\n    GetClientRect(rect);\n\n    if (rect.Width() <= 1 || rect.Height() <= 1)\n        return TRUE;\n\n    CComQIPtr<ID2D1DeviceContext> spContext(*pRenderTarget);\n\n    float dpiX;\n    float dpiY;\n    spContext->GetDpi(&dpiX, &dpiY);\n\n    auto sourceSize = m_sourceSize;\n    auto aspectRatio = m_aspectRatio;\n\n    if (GetDocument()->isOrientationUpend())\n    {\n        std::swap(sourceSize.cx, sourceSize.cy);\n        aspectRatio = 1. / aspectRatio;\n    }\n\n    float scaleW = rect.Width() / (float) sourceSize.cx;\n    float scaleH = rect.Height() / (float) sourceSize.cy;\n\n    D2D1_POINT_2F offset;\n    if (scaleH * aspectRatio <= scaleW) {\n        scaleW = scaleH * aspectRatio;\n        offset.x = (rect.Width() -\n            (sourceSize.cx * scaleW)) / 2.0f;\n        offset.y = 0.0f;\n    }\n    else {\n        scaleH = scaleW / aspectRatio;\n        offset.x = 0.0f;\n        offset.y = (rect.Height() -\n            (sourceSize.cy * scaleH)) / 2.0f;\n    }\n\n    auto transform = D2D1::Matrix3x2F::Identity();\n    if (GetDocument()->isOrientationUpend())\n    {\n        std::swap(transform._11, transform._21);\n        std::swap(transform._12, transform._22);\n    }\n    if (GetDocument()->isOrientationMirrorx())\n    {\n        transform._11 = -transform._11;\n        transform._21 = -transform._21;\n        transform._31 += sourceSize.cx;\n    }\n    if (GetDocument()->isOrientationMirrory())\n    {\n        transform._12 = -transform._12;\n        transform._22 = -transform._22;\n        transform._32 += sourceSize.cy;\n    }\n\n    transform = transform *\n        D2D1::Matrix3x2F::Scale(scaleW, scaleH) *\n        D2D1::Matrix3x2F::Translation(offset.x, offset.y);\n\n    spContext->SetTransform(transform);\n    spContext->Clear(D2D1::ColorF(D2D1::ColorF::Black));\n    if (m_spEffect)\n    {\n        spContext->DrawImage(m_spEffect,\n            //D2D1_INTERPOLATION_MODE_CUBIC\n            D2D1_INTERPOLATION_MODE_LINEAR\n            );\n    }\n\n    spContext->SetTransform(D2D1::Matrix3x2F::Scale(scaleW, scaleH) *\n        D2D1::Matrix3x2F::Translation(offset.x, offset.y));\n\n    if (auto subtitle = GetDocument()->getSubtitle(); !subtitle.empty())\n    {\n        CComPtr<IDWriteTextFormat> pTextFormat;\n        if (SUCCEEDED(AfxGetD2DState()->GetWriteFactory()->CreateTextFormat(\n            L\"MS Sans Serif\",\n            NULL,\n            DWRITE_FONT_WEIGHT_NORMAL,\n            DWRITE_FONT_STYLE_NORMAL,\n            DWRITE_FONT_STRETCH_NORMAL,\n            std::max<int>({ sourceSize.cx / 60, sourceSize.cy / 60, 9 }),\n            L\"\", //locale\n            &pTextFormat)))\n        {\n            D2D1_SIZE_F boundingBox;\n            if (SUCCEEDED(GetTextSize(subtitle, pTextFormat, sourceSize, boundingBox)))\n            {\n                const auto left = (sourceSize.cx - boundingBox.width) / 2;\n                const auto top = sourceSize.cy - boundingBox.height - 2;\n\n                CComPtr<ID2D1SolidColorBrush> pBlackBrush;\n                CComPtr<ID2D1SolidColorBrush> pWhiteBrush;\n                if (SUCCEEDED(spContext->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black, 1.0f), &pBlackBrush)) &&\n                    SUCCEEDED(spContext->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::White, 1.0f), &pWhiteBrush)))\n                {\n                    spContext->DrawText(\n                        subtitle.c_str(),\n                        subtitle.length(),\n                        pTextFormat,\n                        D2D1::RectF(left + 1, top + 1, left + 1 + boundingBox.width, top + 1 + boundingBox.height),\n                        pBlackBrush);\n                    spContext->DrawText(\n                        subtitle.c_str(),\n                        subtitle.length(),\n                        pTextFormat,\n                        D2D1::RectF(left, top, left + boundingBox.width, top + boundingBox.height),\n                        pWhiteBrush);\n                }\n            }\n        }\n    }\n\n    return TRUE;\n}\n\n\nint CPlayerViewD2D::OnCreate(LPCREATESTRUCT lpCreateStruct)\n{\n    if (CView::OnCreate(lpCreateStruct) == -1)\n        return -1;\n\n    GetDocument()->getFrameDecoder()->setFrameListener(m_frameListener.get());\n\n    DragAcceptFiles();\n\n    return 0;\n}\n\n\nvoid CPlayerViewD2D::updateFrame()\n{\n    FrameRenderingData data;\n    if (!GetDocument()->getFrameDecoder()->getFrameRenderingData(&data))\n    {\n        return;\n    }\n\n    CHwndRenderTarget* renderTarget = LockRenderTarget();\n    if (!renderTarget)\n    {\n        return;\n    }\n\n    m_aspectRatio = float(data.aspectNum) / data.aspectDen;\n\n    m_sourceSize.cx = data.width;\n    m_sourceSize.cy = data.height;\n\n    CComQIPtr<ID2D1DeviceContext> spContext(*renderTarget);\n\n    CSingleLock lock(&m_csSurface, TRUE);\n\n    if (!m_spEffect)\n    {\n        HRESULT hr = spContext->CreateEffect(CLSID_CustomI420Effect, &m_spEffect);\n        if (FAILED(hr))\n        {\n            UnlockRenderTarget();\n            return;\n        }\n    }\n\n    // Init bitmap properties in which will store the y (lumi) plane\n    D2D1_BITMAP_PROPERTIES1 props;\n    D2D1_PIXEL_FORMAT       pixFormat;\n\n    pixFormat.alphaMode = D2D1_ALPHA_MODE_STRAIGHT;\n    pixFormat.format = DXGI_FORMAT_A8_UNORM;\n    props.pixelFormat = pixFormat;\n\n    spContext->GetDpi(&props.dpiX, &props.dpiY);\n\n    props.bitmapOptions = D2D1_BITMAP_OPTIONS_NONE;\n    props.colorContext = nullptr;\n\n    CComPtr<ID2D1Bitmap1> yBitmap;\n    HRESULT hr = spContext->CreateBitmap(\n        { static_cast<UINT32>(m_sourceSize.cx), static_cast<UINT32>(m_sourceSize.cy) },\n        data.image[0], data.pitch[0], props, &yBitmap);\n    CComPtr<ID2D1Bitmap1> uBitmap;\n    hr = spContext->CreateBitmap(\n        { static_cast<UINT32>(m_sourceSize.cx / 2), static_cast<UINT32>(m_sourceSize.cy / 2) },\n        data.image[1], data.pitch[1], props, &uBitmap);\n    CComPtr<ID2D1Bitmap1> vBitmap;\n    hr = spContext->CreateBitmap(\n        { static_cast<UINT32>(m_sourceSize.cx / 2), static_cast<UINT32>(m_sourceSize.cy / 2) },\n        data.image[2], data.pitch[2], props, &vBitmap);\n\n    m_spEffect->SetInput(0, yBitmap);\n    m_spEffect->SetInput(1, uBitmap);\n    m_spEffect->SetInput(2, vBitmap);\n\n    UnlockRenderTarget();\n}\n\nLRESULT CPlayerViewD2D::DrawFrame(WPARAM, LPARAM generation)\n{\n    {\n        CSingleLock lock(&m_csSurface, TRUE);\n        DoD2DPaint();\n    }\n\n    GetDocument()->getFrameDecoder()->finishedDisplayingFrame(generation, IFrameDecoder::FINALIZE_DISPLAY);\n\n    return 0;\n}\n\n\nBOOL CPlayerViewD2D::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)\n{\n    if (message == WM_PAINT)\n    {\n        CSingleLock lock(&m_csSurface, TRUE);\n        const BOOL lResult = DoD2DPaint();\n        if (pResult != NULL)\n            *pResult = lResult;\n        return lResult;\n    }\n\n    return __super::OnWndMsg(message, wParam, lParam, pResult);\n}\n\n\nvoid CPlayerViewD2D::OnDropFiles(HDROP hDropInfo)\n{\n    GetDocument()->OnDropFiles(hDropInfo);\n    CView::OnDropFiles(hDropInfo);\n}\n"
  },
  {
    "path": "Player/PlayerViewD2D.h",
    "content": "\n#pragma once\n\n#include <memory>\n\nstruct IFrameListener;\n\nstruct ID2D1Effect;\n\nclass CPlayerViewD2D : public CView\n{\nfriend class FrameListenerD2D;\n\nprotected: // create from serialization only\n    CPlayerViewD2D();\n    DECLARE_DYNCREATE(CPlayerViewD2D)\n\n// Attributes\npublic:\n    CPlayerDoc* GetDocument() const;\n\n// Operations\npublic:\n\n// Overrides\npublic:\n    virtual void OnDraw(CDC* pDC);  // overridden to draw this view\n    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);\nprotected:\n    virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);\n    virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);\n    virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);\n\n    BOOL OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) override;\n\n// Implementation\npublic:\n    virtual ~CPlayerViewD2D();\n#ifdef _DEBUG\n    virtual void AssertValid() const;\n    virtual void Dump(CDumpContext& dc) const;\n#endif\n\nprotected:\n\nprivate:\n\n// Generated message map functions\nprotected:\n    DECLARE_MESSAGE_MAP()\n    afx_msg LRESULT OnDraw2D(WPARAM wParam, LPARAM lParam);\n    afx_msg LRESULT DrawFrame(WPARAM wParam, LPARAM lParam);\npublic:\n    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);\nprotected:\n    void updateFrame();\n\nprivate:\n    std::unique_ptr<IFrameListener> m_frameListener;\n    CSize m_sourceSize;\n    float m_aspectRatio;\n    CComPtr<ID2D1Effect> m_spEffect;\n\n    CCriticalSection m_csSurface;\n\npublic:\n    afx_msg void OnDropFiles(HDROP hDropInfo);\n    afx_msg void OnEditPaste();\n};\n"
  },
  {
    "path": "Player/ReadMe.txt",
    "content": "================================================================================\n    MICROSOFT FOUNDATION CLASS LIBRARY : Player Project Overview\n===============================================================================\n\nThe application wizard has created this Player application for\nyou.  This application not only demonstrates the basics of using the Microsoft\nFoundation Classes but is also a starting point for writing your application.\n\nThis file contains a summary of what you will find in each of the files that\nmake up your Player application.\n\nPlayer.vcxproj\n    This is the main project file for VC++ projects generated using an application wizard.\n    It contains information about the version of Visual C++ that generated the file, and\n    information about the platforms, configurations, and project features selected with the\n    application wizard.\n\nPlayer.vcxproj.filters\n    This is the filters file for VC++ projects generated using an Application Wizard. \n    It contains information about the association between the files in your project \n    and the filters. This association is used in the IDE to show grouping of files with\n    similar extensions under a specific node (for e.g. \".cpp\" files are associated with the\n    \"Source Files\" filter).\n\nPlayer.h\n    This is the main header file for the application.  It includes other\n    project specific headers (including Resource.h) and declares the\n    CPlayerApp application class.\n\nPlayer.cpp\n    This is the main application source file that contains the application\n    class CPlayerApp.\n\nPlayer.rc\n    This is a listing of all of the Microsoft Windows resources that the\n    program uses.  It includes the icons, bitmaps, and cursors that are stored\n    in the RES subdirectory.  This file can be directly edited in Microsoft\n    Visual C++. Your project resources are in 1033.\n\nres\\Player.ico\n    This is an icon file, which is used as the application's icon.  This\n    icon is included by the main resource file Player.rc.\n\nres\\Player.rc2\n    This file contains resources that are not edited by Microsoft\n    Visual C++. You should place all resources not editable by\n    the resource editor in this file.\n\n/////////////////////////////////////////////////////////////////////////////\n\nFor the main frame window:\n    The project includes a standard MFC interface.\n\nMainFrm.h, MainFrm.cpp\n    These files contain the frame class CMainFrame, which is derived from\n    CFrameWnd and controls all SDI frame features.\n\nres\\Toolbar.bmp\n    This bitmap file is used to create tiled images for the toolbar.\n    The initial toolbar and status bar are constructed in the CMainFrame\n    class. Edit this toolbar bitmap using the resource editor, and\n    update the IDR_MAINFRAME TOOLBAR array in Player.rc to add\n    toolbar buttons.\n/////////////////////////////////////////////////////////////////////////////\n\nThe application wizard creates one document type and one view:\n\nPlayerDoc.h, PlayerDoc.cpp - the document\n    These files contain your CPlayerDoc class.  Edit these files to\n    add your special document data and to implement file saving and loading\n    (via CPlayerDoc::Serialize).\n\nPlayerView.h, PlayerView.cpp - the view of the document\n    These files contain your CPlayerView class.\n    CPlayerView objects are used to view CPlayerDoc objects.\n\n\n\n\n/////////////////////////////////////////////////////////////////////////////\n\nOther Features:\n\nPrinting and Print Preview support\n    The application wizard has generated code to handle the print, print setup, and print preview\n    commands by calling member functions in the CView class from the MFC library.\n\n/////////////////////////////////////////////////////////////////////////////\n\nOther standard files:\n\nStdAfx.h, StdAfx.cpp\n    These files are used to build a precompiled header (PCH) file\n    named Player.pch and a precompiled types file named StdAfx.obj.\n\nResource.h\n    This is the standard header file, which defines new resource IDs.\n    Microsoft Visual C++ reads and updates this file.\n\nPlayer.manifest\n\tApplication manifest files are used by Windows XP to describe an applications\n\tdependency on specific versions of Side-by-Side assemblies. The loader uses this\n\tinformation to load the appropriate assembly from the assembly cache or private\n\tfrom the application. The Application manifest  maybe included for redistribution\n\tas an external .manifest file that is installed in the same folder as the application\n\texecutable or it may be included in the executable in the form of a resource.\n/////////////////////////////////////////////////////////////////////////////\n\nOther notes:\n\nThe application wizard uses \"TODO:\" to indicate parts of the source code you\nshould add to or customize.\n\nIf your application uses MFC in a shared DLL, you will need\nto redistribute the MFC DLLs. If your application is in a language\nother than the operating system's locale, you will also have to\nredistribute the corresponding localized resources mfc110XXX.DLL.\nFor more information on both of these topics, please see the section on\nredistributing Visual C++ applications in MSDN documentation.\n\n/////////////////////////////////////////////////////////////////////////////\n"
  },
  {
    "path": "Player/SecondsToString.h",
    "content": "#pragma once\n\n#include <string>\n#include <sstream>\n#include <iomanip>\n\ninline std::basic_string<TCHAR> secondsToString(int seconds, bool milli)\n{\n    using std::setfill;\n    using std::setw;\n\n    std::basic_ostringstream<TCHAR> buffer;\n    if (seconds < (milli? 0 : -999))\n    {\n        buffer << '-';\n        seconds = -seconds;\n    }\n    int ms = seconds % 1000;\n    seconds /= 1000; // towards zero\n    int s = seconds % 60;\n    int m = (seconds / 60) % 60;\n    int h = seconds / 3600;\n\n    if (h > 0)\n    { \n        buffer << h << ':';\n    }\n    buffer << setfill(_T('0')) << setw(2) << m << ':' << setfill(_T('0')) << setw(2) << s;\n    if (milli)\n    {\n        buffer << '.' << setfill(_T('0')) << setw(3) << ms;\n    }\n\n    return buffer.str();\n}\n"
  },
  {
    "path": "Player/StringDifference.cpp",
    "content": "#include \"stdafx.h\"\n#include \"StringDifference.h\"\n\n#include <algorithm>\n\nstatic auto SafePathString(std::basic_string<TCHAR> path)\n{\n    enum\n    {\n        MAX_DIFF_SIZE = 2048\n    };\n    path.append(MAX_DIFF_SIZE, _T('\\0'));\n    return path;\n}\n\n\ntemplate <typename T>\nT reversed(const T& s)\n{\n    return {s.rbegin(), s.rend()};\n}\n\ntemplate<typename T>\nint levenshteinDistance(const T& s1, const T& s2)\n{\n    const int len1 = s1.size() + 1;\n    const int len2 = s2.size() + 1;\n    std::vector<int> dp(len1 * len2);\n\n    for (int i = 0; i < len1; ++i)\n    {\n        dp[i * len2] = i;\n    }\n    for (int j = 0; j < len2; ++j)\n    {\n        dp[j] = j;\n    }\n\n    for (int i = 1; i < len1; ++i)\n    {\n        for (int j = 1; j < len2; ++j)\n        {\n            const int cost = (s1[i - 1] != s2[j - 1]);\n            dp[i * len2 + j] = (std::min)({dp[(i - 1) * len2 + j] + 1,\n                dp[i * len2 + j - 1] + 1, dp[(i - 1) * len2 + j - 1] + cost});\n        }\n    }\n\n    return dp.back();\n}\n\nStringDifference::StringDifference(const Sequence& a, const Sequence& b)\n    : m_diff(a, b),\n      m_reversedDiff(reversed(a), reversed(b)),\n      m_path_b(b),\n      m_sameNames(m_path_b.has_parent_path() && m_path_b.has_stem() &&\n                  m_path_b.stem() == std::filesystem::path(a).stem())\n{\n    if (!m_sameNames)\n    {\n        m_diff.compose();\n        m_reversedDiff.compose();\n    }\n}\n\nStringDifference::Sequence StringDifference::patch(const Sequence& seq) const\n{\n    if (m_sameNames)\n    {\n        return (m_path_b.parent_path() / std::filesystem::path(seq).stem()) +=\n               m_path_b.extension();\n    }\n\n    Sequence s = m_reversedDiff.patch(SafePathString(reversed(seq)));\n    std::reverse(s.begin(), s.begin() + _tcslen(s.c_str()));\n    if (s.empty() || s[0] == 0 || 0 != _taccess(s.c_str(), 04))\n    {\n        s = m_diff.patch(SafePathString(seq));\n        if (s.empty() || s[0] == 0 || 0 != _taccess(s.c_str(), 04))\n        {\n            auto closest = LastResort(seq);\n            if (!closest.empty())\n                return closest;\n        }\n    }\n    s.resize(_tcslen(s.c_str()));\n    return s;\n}\n\nStringDifference::Sequence StringDifference::LastResort(\n    const StringDifference::Sequence& seq) const\n{\n    try\n    {\n        const auto extension = m_path_b.extension();\n        const Sequence name = std::filesystem::path(seq).stem();\n        int minDistance = INT_MAX;\n        std::filesystem::path result_name;\n        for (auto const& dir_entry : std::filesystem::directory_iterator{m_path_b.parent_path()})\n        {\n            if (dir_entry.is_directory())\n                continue;\n            auto path = dir_entry.path();\n            if (_tcsicmp(path.extension().c_str(), extension.c_str()) != 0)\n                continue;\n            const auto stem = path.stem();\n            const int dist = levenshteinDistance(name, static_cast<const Sequence&>(stem));\n            if (dist < minDistance)\n            {\n                minDistance = dist;\n                result_name = stem;\n            }\n            else if (dist == minDistance)\n            {\n                result_name.clear();\n            }\n        }\n        if (!result_name.empty())\n        {\n            auto result = (m_path_b.parent_path() / result_name) += extension;\n            if (equivalent(m_path_b, result))\n                return {};\n            return result;\n        }\n        return {};\n    }\n    catch (const std::exception& ex)\n    {\n        TRACE(\"Exception in StringDifference: %s: %s\\n\", typeid(ex).name(), ex.what());\n        return {};\n    }\n}\n"
  },
  {
    "path": "Player/StringDifference.h",
    "content": "#pragma once\n\n// vcpkg install dtl\n#include <dtl/dtl.hpp>\n\n#include <filesystem>\n\n\nclass StringDifference\n{\n    typedef std::basic_string<TCHAR> Sequence;\n\n    dtl::Diff<TCHAR, std::basic_string<TCHAR>> m_diff, m_reversedDiff;\n    std::filesystem::path m_path_b;\n    bool m_sameNames;\n\n    Sequence LastResort(const StringDifference::Sequence& seq) const;\n\n   public:\n    StringDifference(const Sequence& a, const Sequence& b);\n    Sequence patch(const Sequence& seq) const;\n};\n"
  },
  {
    "path": "Player/YouTuber.cpp",
    "content": "#include \"stdafx.h\"\n\n#include \"YouTuber.h\"\n\n#define YOUTUBE_EXPERIMENT\n\n#ifdef YOUTUBE_EXPERIMENT\n\n#include <Shlobj.h>\n\n#include <boost/python/exec.hpp>\n#include <boost/python/import.hpp>\n#include <boost/python/extract.hpp>\n#include <boost/python.hpp>\n\n#include <boost/log/trivial.hpp>\n#include <boost/log/sources/channel_logger.hpp>\n\n#include <boost/algorithm/string.hpp>\n\n#include <regex>\n#include <fstream>\n#include <iterator>\n#include <streambuf>\n#include <algorithm>\n#include <cctype>\n#include <map>\n#include <memory>\n#include <utility>\n\n#include <tchar.h>\n\n#include \"http_get.h\"\n\n#include \"MemoryMappedFile.h\"\n\nnamespace {\n\n// Parses the value of the active python exception\nstd::string parse_python_exception()\n{\n    namespace py = boost::python;\n\n    PyObject *type_ptr = NULL, *value_ptr = NULL, *traceback_ptr = NULL;\n    PyErr_Fetch(&type_ptr, &value_ptr, &traceback_ptr);\n\n    std::string ret(\"Unfetchable Python error\");\n    if(type_ptr != NULL){\n        py::handle<> h_type(type_ptr);\n        py::str type_pstr(h_type);\n        py::extract<std::string> e_type_pstr(type_pstr);\n        if(e_type_pstr.check())\n            ret = e_type_pstr();\n        else\n            ret = \"Unknown exception type\";\n    }\n    if(value_ptr != NULL){\n        py::handle<> h_val(value_ptr);\n        py::str a(h_val);\n        py::extract<std::string> returned(a);\n        try {\n            if (returned.check())\n                ret += \": \" + returned();\n            else\n                ret += \": Unparseable Python error: \";\n        }\n        catch (const py::error_already_set&) {\n            ret += \": Unparseable Python error: \";\n        }\n    }\n    if(traceback_ptr != NULL){\n        py::handle<> h_tb(traceback_ptr);\n        py::object tb(py::import(\"traceback\"));\n        py::object fmt_tb(tb.attr(\"format_tb\"));\n        py::object tb_list(fmt_tb(h_tb));\n        py::object tb_str(py::str(\"\\n\").join(tb_list));\n        py::extract<std::string> returned(tb_str);\n        if(returned.check())\n            ret += \": \" + returned();\n        else\n            ret += \": Unparseable Python traceback\";\n    }\n    return ret;\n}\n\n\nclass LoggerStream\n{\npublic:\n    void write(const std::string& what)\n    {\n        using namespace boost::log;\n        sources::channel_logger_mt<> logger(keywords::channel = \"python\");\n        BOOST_LOG(logger) << what;\n    }\n    void flush() {}\n};\n\n\nconst char COMBINED_TEMPLATE[] = R\"(import sys, socket, re\nsys.stderr = LoggerStream()\n\ndef install_and_import(package, url=None):\n    import importlib\n    if url is None:\n        url = package\n    try:\n        importlib.import_module(package)\n    except ImportError:\n        import subprocess\n        import os\n        library_dir = os.path.dirname(os.path.abspath(socket.__file__))\n        subprocess.run([library_dir + \"/../scripts/pip3\", \"install\", url])\n    finally:\n        globals()[package] = importlib.import_module(package)\n\n# ---- yt-dlp based getYoutubeUrl ----\ninstall_and_import(\"yt_dlp\", \"https://github.com/yt-dlp/yt-dlp/archive/refs/heads/master.zip\")\n\nfrom urllib.parse import urlencode, urlparse, parse_qs\n\ndef parsePlaylist(url: str, force: bool):\n    # 1. Detect search query (no dots or slashes)\n    if all(ch not in url for ch in \"./\"):\n        parts = url.split()\n        query = \"+\".join(urlencode({\"q\": p})[2:] for p in parts)\n        search_url = f\"ytsearch50:{query}\"\n        return _extract_flat_urls(search_url)\n\n    # 2. URL case\n    parsed = urlparse(url)\n    qs = parse_qs(parsed.query)\n\n    is_list = \"list\" in qs\n    is_channel = _is_channel_url(url)\n\n    # Playlist or channel -> treat as list\n    if is_list or is_channel:\n        return _extract_flat_urls(url)\n\n    # 3. Single video page\n    if force:\n        return _extract_from_video_page(url)\n\n    return []\n\n\ndef _is_channel_url(url: str):\n    \"\"\"Detects YouTube channel URLs but does NOT treat them as results.\"\"\"\n    return any(part in url for part in [\n        \"/channel/\",\n        \"/user/\",\n        \"/c/\",\n        \"/@\"\n    ])\n\n\ndef _extract_flat_urls(yt_url: str):\n    ydl_opts = {\n        \"quiet\": True,\n        \"skip_download\": True,\n        \"extract_flat\": True,\n    }\n\n    with yt_dlp.YoutubeDL(ydl_opts) as ydl:\n        info = ydl.extract_info(yt_url, download=False)\n\n    entries = info.get(\"entries\", [])\n    urls = []\n\n    for e in entries:\n        if \"url\" in e:\n            # Filter out channel URLs\n            if not _is_channel_url(e[\"url\"]):\n                urls.append(e[\"url\"])\n\n    return urls\n\n\ndef _extract_from_video_page(video_url: str):\n    ydl_opts = {\n        \"quiet\": True,\n        \"skip_download\": True,\n        \"extract_flat\": False,\n    }\n\n    with yt_dlp.YoutubeDL(ydl_opts) as ydl:\n        info = ydl.extract_info(video_url, download=False)\n\n    urls = []\n\n    # The video itself\n    if \"webpage_url\" in info:\n        urls.append(info[\"webpage_url\"])\n\n    # Playlist URLs (if video is inside a playlist)\n    for pl in info.get(\"playlists\", []):\n        if \"id\" in pl:\n            urls.append(f\"https://www.youtube.com/playlist?list={pl['id']}\")\n\n    # Try to approximate \"related videos\" using search\n    title = info.get(\"title\")\n    if title:\n        search_query = f\"ytsearch10:{title}\"\n        with yt_dlp.YoutubeDL({\"quiet\": True, \"extract_flat\": True}) as ydl:\n            s = ydl.extract_info(search_query, download=False)\n            for e in s.get(\"entries\", []):\n                if \"url\" in e and not _is_channel_url(e[\"url\"]):\n                    urls.append(e[\"url\"])\n\n    # Deduplicate\n    urls = list(dict.fromkeys(urls))\n\n    return urls\n\n\ndef _iter_formats(info):\n    if not info:\n        return []\n    if isinstance(info, dict) and 'entries' in info and info['entries']:\n        for e in info['entries']:\n            if e:\n                info = e\n                break\n    if isinstance(info, dict) and 'requested_formats' in info and info['requested_formats']:\n        return info['requested_formats']\n    if isinstance(info, dict) and 'formats' in info and info['formats']:\n        return info['formats']\n    if isinstance(info, dict) and 'url' in info:\n        return [info]\n    return []\n\ndef _is_usable_video_format(f):\n    vcodec = f.get('vcodec')\n    proto = f.get('protocol', '')\n    if not vcodec or vcodec == 'none':\n        return False\n    if vcodec.startswith('av01'):\n        return False\n    if proto == 'm3u8_native' or proto == 'm3u8':\n        return False\n    return True\n\ndef _is_usable_audio_format(f):\n    vcodec = f.get('vcodec', 'none')\n    proto = f.get('protocol', '')\n    if vcodec != 'none':\n        return False\n    if proto == 'm3u8_native' or proto == 'm3u8':\n        return False\n    return 'audio_channels' in f and f.get('audio_channels') is not None or 'abr' in f\n\ndef getYoutubeUrl(url, adaptive):\n    socket.setdefaulttimeout(10)\n    base_opts = {\n        'noplaylist': True,\n        'quiet': True,\n        'skip_download': True,\n    }\n    ydl_opts = base_opts.copy()\n    ydl_opts['format'] = 'bestvideo+bestaudio' if adaptive else 'best'\n    with yt_dlp.YoutubeDL(ydl_opts) as ydl:\n        info = ydl.extract_info(url, download=False)\n    formats = _iter_formats(info)\n    if adaptive:\n        video_candidates = [f for f in formats if _is_usable_video_format(f)]\n        if video_candidates:\n            best_video = max(video_candidates, key=lambda f: (f.get('height') or 0, f.get('tbr') or 0))\n            video_url = best_video.get('url')\n        else:\n            video_url = info.get('url')\n        audio_candidates = [f for f in formats if _is_usable_audio_format(f)]\n        if audio_candidates:\n            best_audio = max(audio_candidates, key=lambda f: (f.get('audio_channels') or 0, f.get('abr') or 0))\n            audio_url = best_audio.get('url')\n        else:\n            any_audio = next((f for f in formats if f.get('vcodec') == 'none' and f.get('url')), None)\n            audio_url = any_audio.get('url') if any_audio else None\n        return (video_url, audio_url)\n    combined_candidates = [f for f in formats if f.get('vcodec') != 'none' and f.get('audio_channels') is not None and not f.get('vcodec','').startswith('av01') and f.get('protocol') not in ('m3u8_native', 'm3u8')]\n    if not combined_candidates:\n        combined_candidates = [f for f in formats if 'url' in f]\n    best_combined = max(combined_candidates, key=lambda f: (f.get('height') or 0, f.get('tbr') or 0, f.get('abr') or 0))\n    return best_combined.get('url')\n\n# ---- youtube_transcript_api based getYoutubeTranscript ----\ninstall_and_import(\"youtube_transcript_api\", \"https://github.com/jdepoix/youtube-transcript-api/archive/master.zip\")\n\n_YT_ID_RE = re.compile(\n    r'(?:v=|\\/v\\/|youtu\\.be\\/|\\/embed\\/|\\/shorts\\/|watch\\?.*v=)([A-Za-z0-9_-]{11})'\n)\n\ndef extract_youtube_id(url_or_id: str) -> str:\n    if not isinstance(url_or_id, str):\n        raise ValueError(\"video id or url must be a string\")\n    url_or_id = url_or_id.strip()\n    if len(url_or_id) == 11 and re.fullmatch(r'[A-Za-z0-9_-]{11}', url_or_id):\n        return url_or_id\n    m = _YT_ID_RE.search(url_or_id)\n    if m:\n        return m.group(1)\n    q = re.search(r'[?&]v=([A-Za-z0-9_-]{11})', url_or_id)\n    if q:\n        return q.group(1)\n    raise ValueError(\"Could not extract YouTube video id from input\")\n\ndef getYoutubeTranscript(url_or_id: str):\n    video_id = extract_youtube_id(url_or_id)\n    return youtube_transcript_api.YouTubeTranscriptApi().fetch(video_id).to_raw_data()\n)\";\n\n\nint from_hex(char ch)\n{\n    return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;\n}\n\nstd::string UrlUnescapeString(const std::string& s)\n{\n    std::istringstream ss(s);\n    std::string result;\n    std::getline(ss, result, '%');\n    std::string buffer;\n    while (std::getline(ss, buffer, '%'))\n    {\n        if (buffer.size() >= 2)\n        {\n            result += char((from_hex(buffer[0]) << 4) | from_hex(buffer[1])) + buffer.substr(2);\n        }\n    }\n    return result;\n}\n\nvoid hexchar(unsigned char c, unsigned char &hex1, unsigned char &hex2)\n{\n    hex1 = c / 16;\n    hex2 = c % 16;\n    hex1 += hex1 <= 9 ? '0' : 'a' - 10;\n    hex2 += hex2 <= 9 ? '0' : 'a' - 10;\n}\n\nstd::string urlencode(const std::string& s)\n{\n    std::string v;\n    for (char c : s)\n    {\n        if (std::isalnum(static_cast<unsigned char>(c)) ||\n            c == '-' || c == '_' || c == '.' || c == '!' || c == '~' ||\n            c == '*' || c == '\\'' || c == '(' || c == ')')\n        {\n            v.push_back(c);\n        }\n        else if (c == ' ')\n        {\n            v.push_back('+');\n        }\n        else\n        {\n            v.push_back('%');\n            unsigned char d1, d2;\n            hexchar(c, d1, d2);\n            v.push_back(d1);\n            v.push_back(d2);\n        }\n    }\n\n    return v;\n}\n\n// Extracts a single URL from s. Accepts URLs with http or https schemes,\n// or scheme-less URLs that start with a valid host (e.g., \"example.com\" or \"www.example.com\").\n// Rejects inputs that include a non-http(s) scheme (e.g., \"ftp://\", \"htp://\").\n// On success sets s to the matched URL (including path, query and fragment) and returns true.\n// The match is conservative: it stops at whitespace and common delimiters < > \" ' ( ).\n// If the input may be percent-escaped, keep UrlUnescapeString available; we try both raw and unescaped.\nbool extractHttpOrHostUrl(std::string& s)\n{\n    // scheme: optional, but if present must be http or https\n    // host: domain (labels + tld), localhost or IPv4\n    // port: optional\n    // path+query+fragment: optional, but must preserve ? and # if present\n    static const std::regex url_regex(\n        R\"((?:https?:\\/\\/)?(?:(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\\.)+[A-Za-z]{2,}|localhost|\\d{1,3}(?:\\.\\d{1,3}){3})(?::\\d{1,5})?(?:\\/[^\\s\\\"\\'<>()]*)?)\",\n        std::regex::icase\n    );\n\n    std::string copy = s;\n    for (int unescaped = 0; unescaped < 2; ++unescaped)\n    {\n        std::smatch m;\n        if (std::regex_search(copy, m, url_regex))\n        {\n            // keep the full matched length so query params and fragments remain\n            s = copy.substr(m.position(), m.length());\n            // If caller expects the URL to start at the match position and include the rest\n            // of the original string, change to: s = copy.substr(m.position());\n            return true;\n        }\n        if (!unescaped)\n        {\n            // If you have a UrlUnescapeString implementation, use it here to try unescaped input.\n            // If not needed, remove this block or leave it as a no-op.\n            copy = UrlUnescapeString(copy);\n        }\n    }\n\n    return false;\n}\n\nstd::string loadScriptText(const TCHAR* name)\n{\n    TCHAR strPath[MAX_PATH]{};\n    SHGetSpecialFolderPath(\n        nullptr,\n        strPath,\n        CSIDL_LOCAL_APPDATA,\n        FALSE);\n\n    PathAppend(strPath, name);\n\n    std::ifstream file(strPath, std::ios::in | std::ios::binary);\n\n    if (!file)\n        return {};\n\n    std::ostringstream contents;\n    contents << file.rdbuf();\n\n    BOOST_LOG_TRIVIAL(trace) << \"loadScriptText() script loaded: \\\"\" << name << \"\\\"\";\n\n    return contents.str();\n}\n\nauto getLoggerStream()\n{\n    return boost::python::class_<LoggerStream>(\"LoggerStream\")\n        .def(\"write\", &LoggerStream::write)\n        .def(\"flush\", &LoggerStream::flush);\n}\n\n// Execute second application instance with -check_python flag\n// and return true if exit code is 0\nbool isPythonInstalled()\n{\n    STARTUPINFO si = { sizeof(si) };\n    PROCESS_INFORMATION pi;\n    TCHAR szCmdline[MAX_PATH + 20] = _T(\"\\\"\");\n    auto len = GetModuleFileName(NULL, szCmdline + 1, ARRAYSIZE(szCmdline) - 1);\n    _tcscpy_s(szCmdline + len + 1, ARRAYSIZE(szCmdline) - len - 1, _T(\"\\\" -check_python\"));\n    if (!CreateProcess(NULL, szCmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))\n    {\n        return false;\n    }\n\n    DWORD exitCode;\n\n    bool ok = WaitForSingleObject(pi.hProcess, 5000) == WAIT_OBJECT_0\n        && GetExitCodeProcess(pi.hProcess, &exitCode)\n        && exitCode == 0;\n\n    CloseHandle(pi.hProcess);\n    CloseHandle(pi.hThread);\n\n    return ok;\n}\n\n// Shared Python namespace loader/holder\nbool EnsureSharedPythonNamespaceLoaded(boost::python::object& outNamespace)\n{\n    using namespace boost::python;\n\n    static bool s_loaded = false;\n    static bool s_failed = false;\n    static object s_namespace;\n\n    if (s_failed)\n        return false;\n\n    if (s_loaded)\n    {\n        outNamespace = s_namespace;\n        return true;\n    }\n\n    s_failed = true;\n\n    if (!isPythonInstalled())\n    {\n        AfxMessageBox(_T(\"Matching Python is not installed: \") _T(PY_VERSION)\n#ifdef _WIN64\n                          _T(\" (64 bits)\")\n#else\n                          _T(\" (32 bits)\")\n#endif\n        );\n        return false;\n    }\n\n    Py_Initialize();\n    if (!Py_IsInitialized())\n    {\n        BOOST_LOG_TRIVIAL(error) << \"Py_Initialize failed\";\n        return false;\n    }\n\n    // Add atexit finalize guard (optional)\n    atexit(Py_Finalize);\n\n    try {\n        PyObject* sysPath = PySys_GetObject(\"path\");\n        object path(borrowed(sysPath));\n        const auto length = len(path);\n        std::vector<std::string> sysPathList;\n        for (int i = 0; i < length; ++i)\n        {\n            std::string v{extract<std::string>(path[i])};\n            v += \"/site-packages\";\n            if (_taccess(CA2T(v.c_str(), CP_UTF8), 0) == 0)\n            {\n                sysPathList.push_back(std::move(v));\n            }\n        }\n\n        for (const auto& v : sysPathList)\n        {\n            PyList_Insert(sysPath, 0, PyUnicode_FromString(v.c_str()));\n        }\n\n        // Load script text from local override if present; otherwise use combined template\n        const auto localScript = loadScriptText(_T(\"getYoutubeCombined.py\"));\n        const char* scriptToExec = localScript.empty() ? COMBINED_TEMPLATE : localScript.c_str();\n\n        object main = import(\"__main__\");\n        object global(main.attr(\"__dict__\"));\n\n        // inject LoggerStream class to python\n        global[\"LoggerStream\"] = getLoggerStream();\n\n        exec(scriptToExec, global, global);\n\n        s_namespace = global;\n        s_loaded = true;\n        s_failed = false;\n        outNamespace = s_namespace;\n        return true;\n    }\n    catch (const error_already_set&)\n    {\n        BOOST_LOG_TRIVIAL(error) << \"Shared python bootstrap error \\\"\" << parse_python_exception() << \"\\\"\";\n        PyErr_Clear();\n        return false;\n    }\n    catch (const std::exception& ex)\n    {\n        BOOST_LOG_TRIVIAL(error) << \"Shared python bootstrap exception \\\"\" << ex.what() << \"\\\"\";\n        return false;\n    }\n}\n\n\nclass YouTubePlaylistDealer\n{\npublic:\n    YouTubePlaylistDealer();\n    ~YouTubePlaylistDealer() = default;\n\n    bool isValid() const { return !!m_func; }\n    bool getPlaylist(const std::string& url, bool force, std::vector<std::string>& out);\n\nprivate:\n    boost::python::object m_func;\n};\n\nYouTubePlaylistDealer::YouTubePlaylistDealer()\n{\n    using namespace boost::python;\n    try\n    {\n        object ns;\n        if (!EnsureSharedPythonNamespaceLoaded(ns))\n            return;\n\n        try {\n            m_func = ns[\"parsePlaylist\"];\n        }\n        catch (const error_already_set&) {\n            BOOST_LOG_TRIVIAL(error)\n                << \"YouTubePlaylistDealer: parsePlaylist not found in shared python namespace: \"\n                << parse_python_exception();\n            PyErr_Clear();\n        }\n    }\n    catch (const std::exception& ex)\n    {\n        BOOST_LOG_TRIVIAL(error)\n            << \"YouTubePlaylistDealer bootstrap exception \\\"\" << ex.what() << \"\\\"\";\n    }\n    catch (const boost::python::error_already_set&)\n    {\n        BOOST_LOG_TRIVIAL(error)\n            << \"YouTubePlaylistDealer bootstrap python error \\\"\" << parse_python_exception() << \"\\\"\";\n        PyErr_Clear();\n    }\n}\n\nbool YouTubePlaylistDealer::getPlaylist(const std::string& url, bool force, std::vector<std::string>& out)\n{\n    BOOST_LOG_TRIVIAL(trace)\n        << \"YouTubePlaylistDealer::getPlaylist() url = \\\"\" << url << \"\\\" force = \" << force;\n\n    using namespace boost::python;\n\n    if (!isValid())\n        return false;\n\n    try\n    {\n        object v = m_func(url, force);\n        if (v.is_none())\n            return false;\n\n        const auto length = len(v);\n        out.reserve(length);\n\n        for (int i = 0; i < length; ++i)\n        {\n            object el = v[i];\n            std::string s = extract<std::string>(el);\n            out.push_back(std::move(s));\n        }\n\n        return true;\n    }\n    catch (const error_already_set&)\n    {\n        BOOST_LOG_TRIVIAL(error)\n            << \"YouTubePlaylistDealer python error \\\"\" << parse_python_exception() << \"\\\"\";\n        PyErr_Clear();\n    }\n    catch (const std::exception& ex)\n    {\n        BOOST_LOG_TRIVIAL(error)\n            << \"YouTubePlaylistDealer exception \\\"\" << ex.what() << \"\\\"\";\n    }\n\n    return false;\n}\n\n\nclass YouTubeDealer\n{\npublic:\n    YouTubeDealer();\n    ~YouTubeDealer() = default;\n\n    bool isValid() const { return !!m_func; }\n    std::vector<std::string> getYoutubeUrl(const std::string& url, bool adaptive);\n\nprivate:\n    boost::python::object m_func;\n};\n\nYouTubeDealer::YouTubeDealer()\n{\n    using namespace boost::python;\n    try\n    {\n        object ns;\n        if (!EnsureSharedPythonNamespaceLoaded(ns))\n            return;\n\n        // Attempt to get callable 'getYoutubeUrl' from shared namespace\n        try {\n            m_func = ns[\"getYoutubeUrl\"];\n        }\n        catch (const error_already_set&) {\n            BOOST_LOG_TRIVIAL(error) << \"YouTubeDealer: getYoutubeUrl not found in shared python namespace: \" << parse_python_exception();\n            PyErr_Clear();\n        }\n    }\n    catch (const std::exception& ex)\n    {\n        BOOST_LOG_TRIVIAL(error) << \"YouTubeDealer bootstrap exception \\\"\" << ex.what() << \"\\\"\";\n    }\n    catch (const boost::python::error_already_set&)\n    {\n        BOOST_LOG_TRIVIAL(error) << \"YouTubeDealer bootstrap python error \\\"\" << parse_python_exception() << \"\\\"\";\n        PyErr_Clear();\n    }\n}\n\nstd::vector<std::string> YouTubeDealer::getYoutubeUrl(const std::string& url, bool adaptive)\n{\n    BOOST_LOG_TRIVIAL(trace) << \"YouTubeDealer::getYoutubeUrl() url = \\\"\" << url << \"\\\"\";\n    using namespace boost::python;\n\n    if (!isValid())\n        return {};\n\n    try\n    {\n        object py_result = m_func(url, adaptive);\n\n        if (py_result.is_none())\n            return {};\n\n        extract<std::string> as_str(py_result);\n        if (as_str.check())\n            return { as_str() };\n\n        std::vector<std::string> result;\n        for (stl_input_iterator<object> it(py_result), end; it != end; ++it)\n        {\n            extract<std::string> elem_str(*it);\n            if (elem_str.check())\n            {\n                result.push_back(elem_str());\n            }\n            else\n            {\n                result.push_back(extract<std::string>(str(*it))());\n            }\n        }\n        return result;\n    }\n    catch (const error_already_set&)\n    {\n        BOOST_LOG_TRIVIAL(error) << \"YouTubeDealer python error \\\"\" << parse_python_exception() << \"\\\"\";\n        PyErr_Clear();\n    }\n    catch (const std::exception& ex)\n    {\n        BOOST_LOG_TRIVIAL(error) << \"YouTubeDealer exception \\\"\" << ex.what() << \"\\\"\";\n    }\n\n    return {};\n}\n\n\nclass YouTubeTranscriptDealer\n{\npublic:\n    YouTubeTranscriptDealer();\n    ~YouTubeTranscriptDealer() = default;\n\n    bool isValid() const { return !!m_func; }\n    bool getYoutubeTranscripts(const std::string& id, AddYoutubeTranscriptCallback cb);\n\nprivate:\n    boost::python::object m_func;\n};\n\nYouTubeTranscriptDealer::YouTubeTranscriptDealer()\n{\n    using namespace boost::python;\n    try\n    {\n        object ns;\n        if (!EnsureSharedPythonNamespaceLoaded(ns))\n            return;\n\n        try {\n            m_func = ns[\"getYoutubeTranscript\"];\n        }\n        catch (const error_already_set&) {\n            BOOST_LOG_TRIVIAL(error) << \"YouTubeTranscriptDealer: getYoutubeTranscript not found in shared python namespace: \" << parse_python_exception();\n            PyErr_Clear();\n        }\n    }\n    catch (const std::exception& ex)\n    {\n        BOOST_LOG_TRIVIAL(error) << \"YouTubeTranscriptDealer bootstrap exception \\\"\" << ex.what() << \"\\\"\";\n    }\n    catch (const boost::python::error_already_set&)\n    {\n        BOOST_LOG_TRIVIAL(error) << \"YouTubeTranscriptDealer bootstrap python error \\\"\" << parse_python_exception() << \"\\\"\";\n        PyErr_Clear();\n    }\n}\n\nbool YouTubeTranscriptDealer::getYoutubeTranscripts(const std::string& id, AddYoutubeTranscriptCallback cb)\n{\n    BOOST_LOG_TRIVIAL(trace) << \"YouTubeTranscriptDealer::getYoutubeTranscripts() id = \\\"\" << id << \"\\\"\";\n    using namespace boost::python;\n    if (!isValid())\n        return false;\n\n    try\n    {\n        object v = m_func(id);\n        if (v.is_none())\n            return false;\n\n        const auto length = len(v);\n        for (int i = 0; i < length; ++i)\n        {\n            object el = v[i];\n            std::string text = extract<std::string>(el[\"text\"]);\n            boost::algorithm::trim_right(text);\n            if (!text.empty())\n            {\n                double start = extract<double>(el[\"start\"]);\n                double duration = extract<double>(el[\"duration\"]);\n                cb(start, duration, text);\n            }\n        }\n        return true;\n    }\n    catch (const error_already_set&)\n    {\n        BOOST_LOG_TRIVIAL(error) << \"YouTubeTranscriptDealer python error \\\"\" << parse_python_exception() << \"\\\"\";\n        PyErr_Clear();\n    }\n    catch (const std::exception& ex)\n    {\n        BOOST_LOG_TRIVIAL(error) << \"YouTubeTranscriptDealer exception \\\"\" << ex.what() << \"\\\"\";\n    }\n\n    return false;\n}\n\nstd::vector<std::string> DoParsePlaylist(\n    const char* const pDataBegin, const char* const pDataEnd, bool includeLists = true)\n{\n    std::vector<std::string> result;\n\n    auto doSearch = [pDataBegin, pDataEnd, &result](const auto& watch, const char* prefix) {\n        enum { WATCH_SIZE = sizeof(watch) / sizeof(watch[0]) - 1 };\n        auto pData = pDataBegin;\n        while ((pData = std::search(pData, pDataEnd, std::begin(watch), std::prev(std::end(watch)))) != pDataEnd)\n        {\n            const auto localEnd = std::find_if(pData + WATCH_SIZE, pDataEnd, [](char ch) {\n                return ch == '&' || ch == '\"' || ch == '\\'' || ch == '\\\\' || std::isspace(static_cast<unsigned char>(ch));\n                });\n            auto el = prefix + std::string(pData, localEnd);\n            if (std::find(result.begin(), result.end(), el) == result.end())\n                result.push_back(std::move(el));\n            pData += WATCH_SIZE;\n        }\n        };\n\n    doSearch(\"/watch?v=\", \"https://www.youtube.com\");\n    doSearch(\"youtu.be/\", \"https://\");\n    if (includeLists)\n    {\n        doSearch(\"/playlist?list=\", \"https://www.youtube.com\");\n    }\n\n    return result;\n}\n\n} // namespace\n\nvoid CheckPython()\n{\n    Py_Initialize();\n\n    if (!Py_IsInitialized())\n    {\n        exit(1);\n    }\n\n    atexit(Py_Finalize);\n\n    if (!_PyThreadState_UncheckedGet())\n    {\n        exit(1);\n    }\n\n    PyObject* sysPath = PySys_GetObject(\"path\");\n    if (!sysPath)\n    {\n        exit(1);\n    }\n\n    try {\n        boost::python::object path(boost::python::borrowed(sysPath));\n        const auto length = len(path);\n        if (length < 1)\n        {\n            exit(1);\n        }\n\n        std::string v{ boost::python::extract<std::string>(path[0]) };\n        if (v.empty())\n        {\n            exit(1);\n        }\n    }\n    catch (...) {\n        exit(1);\n    }\n}\n\nstd::vector<std::string> ParsePlaylist(std::string url, bool force)\n{\n    std::vector<std::string> result;\n\n    if (!url.empty())\n    {\n        CWaitCursor wait;\n        static YouTubePlaylistDealer dealer;\n\n        if (dealer.isValid())\n            dealer.getPlaylist(url, force, result);\n    }\n\n    return result;\n}\n\nstd::vector<std::string> ParsePlaylistFile(const TCHAR* fileName)\n{\n    MemoryMappedFile memoryMappedFile;\n    if (!memoryMappedFile.MapFlie(fileName))\n        return{};\n    auto* const pData = static_cast<const char*>(memoryMappedFile.data());\n    return DoParsePlaylist(pData, pData + memoryMappedFile.size());\n}\n\nstd::vector<std::string> ParsePlaylistText(const std::string& text)\n{\n    if (text.empty())\n    {\n        return{};\n    }\n    auto* const pData = text.data();\n    return DoParsePlaylist(pData, pData + text.size());\n}\n\ninline bool isHttpStatusOk(int status)\n{\n    const bool result = status == 200 || status == 302;\n    if (!result)\n        BOOST_LOG_TRIVIAL(trace) << \"HTTP error status: \" << status;\n    return result;\n}\n\nstd::pair<std::string, std::string> getYoutubeUrl(std::string url, bool adaptive, bool useHHO)\n{\n    enum { ATTEMPTS_NUMBER = 2 };\n\n    if (extractHttpOrHostUrl(url))\n    {\n        static std::map<std::string, std::pair<std::string, std::string>> mapToDownloadLinks[2];\n        auto it = mapToDownloadLinks[adaptive].find(url);\n        if (it != mapToDownloadLinks[adaptive].end())\n        {\n            if (isHttpStatusOk(HttpGetStatus(it->second.first, useHHO))\n                    && (it->second.second.empty() || isHttpStatusOk(HttpGetStatus(it->second.second, useHHO))))\n                return it->second;\n            else\n                mapToDownloadLinks[adaptive].erase(it);\n        }\n\n        CWaitCursor wait;\n        static YouTubeDealer buddy;\n        if (buddy.isValid())\n        {\n            for (int j = 0; j < ATTEMPTS_NUMBER; ++j)\n            {\n                auto urls = buddy.getYoutubeUrl(url, adaptive);\n                if (!urls.empty())\n                {\n                    const auto status = HttpGetStatus(urls[0], useHHO);\n                    BOOST_LOG_TRIVIAL(trace) << \"Resource status: \" << status;\n                    if (isHttpStatusOk(status))\n                    {\n                        if (urls.size() > 1)\n                        {\n                            for (int i = 1; i < urls.size(); ++i)\n                            {\n                                const auto status = HttpGetStatus(urls[i], useHHO);\n                                BOOST_LOG_TRIVIAL(trace) << \"Resource status: \" << status;\n                                if (isHttpStatusOk(status))\n                                {\n                                    return mapToDownloadLinks[adaptive][url] = { urls[i], urls[0] };\n                                }\n                            }\n                        }\n                        else\n                        {\n                            return mapToDownloadLinks[adaptive][url] = { urls[0],{} };\n                        }\n                    }\n                    Sleep(50);\n                }\n            }\n        }\n\n        return{};\n    }\n\n    return{ url, {} };\n}\n\nbool getYoutubeTranscripts(std::string url, AddYoutubeTranscriptCallback cb)\n{\n    if (extractHttpOrHostUrl(url))\n    {\n        CWaitCursor wait;\n        static YouTubeTranscriptDealer buddy;\n        if (buddy.isValid())\n            return buddy.getYoutubeTranscripts(url, cb);\n    }\n\n    return false;\n}\n\n#else // YOUTUBE_EXPERIMENT\n\nvoid CheckPython() {}\n\nstd::vector<std::string> ParsePlaylist(std::string, bool)\n{\n    return{};\n}\n\nstd::vector<std::string> ParsePlaylistFile(const TCHAR*)\n{\n    return{};\n}\n\nstd::vector<std::string> ParsePlaylistText(const std::string&)\n{\n    return{};\n}\n\nstd::pair<std::string, std::string> getYoutubeUrl(std::string url, bool /*adaptive*/, bool /*useHHO*/)\n{\n    return{ url, {} };\n}\n\nbool getYoutubeTranscripts(std::string, AddYoutubeTranscriptCallback)\n{\n    return false;\n}\n\n#endif // YOUTUBE_EXPERIMENT\n"
  },
  {
    "path": "Player/YouTuber.h",
    "content": "#pragma once\n\n#include <string>\n#include <functional>\n#include <vector>\n\nvoid CheckPython();\n\nstd::vector<std::string> ParsePlaylist(std::string url, bool force);\n\nstd::vector<std::string> ParsePlaylistFile(const TCHAR* fileName);\n\nstd::vector<std::string> ParsePlaylistText(const std::string& text);\n\nstd::pair<std::string, std::string> getYoutubeUrl(std::string url, bool adaptive, bool useHHO);\n\n// start, duration, text\ntypedef std::function<void(double, double, const std::string&)> AddYoutubeTranscriptCallback;\n\nbool getYoutubeTranscripts(std::string url, AddYoutubeTranscriptCallback cb);\n"
  },
  {
    "path": "Player/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by Player.rc\n//\n#define IDD_ABOUTBOX                    100\n#define IDD_DIALOGBAR_PLAYER_CONTROL    103\n#define ID_VIEW_CUSTOMIZE               126\n#define IDR_MAINFRAME                   128\n#define IDS_TOOLBAR_CUSTOMIZE           129\n#define IDR_PlayerTYPE                  130\n#define IDS_PlayerControl               130\n#define IDS_PLAYER_CONTROL              130\n#define IDS_RANGE                       131\n#define IDS_PAUSE                       132\n#define IDS_PLAY                        133\n#define IDI_PAUSE                       311\n#define IDI_PLAY                        312\n#define IDI_AUDIO                       313\n#define IDI_AUDIO_OFF                   314\n#define IDI_FULL_SCREEN                 315\n#define IDD_DIALOG_OPEN_URL             317\n#define IDD_DIALOGBAR_RANGE             319\n#define IDR_LAUNCH                      320\n#define IDD_DIALOG_VIDEO_FILTER         321\n#define IDC_PROGRESS_SLIDER             1000\n#define IDC_PLAY_PAUSE                  1001\n#define IDC_AUDIO_ON_OFF                1002\n#define IDC_VOLUME_SLIDER               1003\n#define IDC_CURRENT_TIME                1004\n#define IDC_TOTAL_TIME                  1005\n#define IDC_EDIT_URL                    1005\n#define IDC_FULL_SCREEN                 1006\n#define IDC_FRAME_STEP                  1007\n#define IDC_START                       1008\n#define IDC_EDIT_START                  1010\n#define IDC_START_RESET                 1011\n#define IDC_END                         1012\n#define IDC_EDIT_END                    1013\n#define IDC_END_RESET                   1014\n#define IDC_PARSE                       1016\n#define IDC_VIDEO_PROPERTIES            1017\n#define IDC_APP_NAME_VERSION            1018\n#define IDC_EDIT_INPUT_FORMAT           1019\n#define IDC_LOSSLESS_CUT                1020\n#define IDC_VIDEO_FILTER                1021\n#define IDC_ENABLE_VIDEO_FILTER         1022\n#define ID_TRACK1_DUMMY                 32771\n#define ID_AUTOPLAY                     32775\n#define ID_LOOPING                      32776\n#define ID_VIDEO_SPEED1                 32777\n#define ID_VIDEO_SPEED2                 32778\n#define ID_VIDEO_SPEED3                 32779\n#define ID_VIDEO_SPEED4                 32780\n#define ID_VIDEO_SPEED5                 32781\n#define ID_VIDEO_SPEED6                 32782\n#define ID_VIDEO_SPEED7                 32783\n#define ID_NIGHTCORE                    32784\n#define ID_OPENSUBTITLESFILE            32785\n#define ID_COPY_URL_TO_CLIPBOARD        32786\n#define ID_MAXIMALRESOLUTION            32787\n#define ID_HW_ACCELERATION              32788\n#define ID_AUDIO_OPENSUBTITLES          32789\n#define ID_FIRST_SUBTITLE_DUMMY         32790\n#define ID_SUPER_RESOLUTION             32791\n#define ID_ORIENTATION_MIRRORX          32792\n#define ID_ORIENTATION_MIRRORY          32793\n#define ID_ORIENTATION_UPEND            32794\n#define ID_ORIENTATION_DO_NOTHING       32795\n#define ID_ORIENTATION_RORATE_90        32796\n#define ID_ORIENTATION_RORATE_180       32797\n#define ID_ORIENTATION_RORATE_270       32798\n#define ID_FIX_ENCODING                 32799\n#define ID_CONVERT_VIDEOS_INTO_COMPATIBLE_FORMAT 32800\n#define ID_OPEN_AUDIO_FILE              32801\n#define ID_USING_HHO                    32802\n#define ID_VIDEO_FILTER                 32803\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        323\n#define _APS_NEXT_COMMAND_VALUE         32804\n#define _APS_NEXT_CONTROL_VALUE         1023\n#define _APS_NEXT_SYMED_VALUE           317\n#endif\n#endif\n"
  },
  {
    "path": "Player/stdafx.cpp",
    "content": "\n// stdafx.cpp : source file that includes just the standard includes\n// Player.pch will be the pre-compiled header\n// stdafx.obj will contain the pre-compiled type information\n\n#include \"stdafx.h\"\n\n\n"
  },
  {
    "path": "Player/stdafx.h",
    "content": "\n// stdafx.h : include file for standard system include files,\n// or project specific include files that are used frequently,\n// but are changed infrequently\n\n#pragma once\n\n#ifndef VC_EXTRALEAN\n#define VC_EXTRALEAN            // Exclude rarely-used stuff from Windows headers\n#endif\n\n#include \"targetver.h\"\n\n#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // some CString constructors will be explicit\n\n// turns off MFC's hiding of some common and often safely ignored warning messages\n#define _AFX_ALL_WARNINGS\n\n#include <afxwin.h>         // MFC core and standard components\n#include <afxext.h>         // MFC extensions\n\n\n\n\n\n#ifndef _AFX_NO_OLE_SUPPORT\n#include <afxdtctl.h>           // MFC support for Internet Explorer 4 Common Controls\n#endif\n#ifndef _AFX_NO_AFXCMN_SUPPORT\n#include <afxcmn.h>             // MFC support for Windows Common Controls\n#endif // _AFX_NO_AFXCMN_SUPPORT\n\n#include <afxcontrolbars.h>     // MFC support for ribbons and control bars\n\n\n\n#ifdef _UNICODE\n#if defined _M_IX86\n#pragma comment(linker,\"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#elif defined _M_X64\n#pragma comment(linker,\"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#else\n#pragma comment(linker,\"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#endif\n#endif\n"
  },
  {
    "path": "Player/targetver.h",
    "content": "#pragma once\n\n// Including SDKDDKVer.h defines the highest available Windows platform.\n\n// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and\n// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.\n\n#include <WinSDKVer.h>\n\n#define _WIN32_WINNT  _WIN32_WINNT_WIN8\n#define NTDDI_VERSION NTDDI_WIN8\n#define WINVER        _WIN32_WINNT_WIN8\n#define _WIN32_IE     _WIN32_IE_WIN8\n\n#include <SDKDDKVer.h>\n"
  },
  {
    "path": "Player/update_version.cmd",
    "content": "<nul set /p=\"#define GIT_COMMIT \" > %~dp0\\version.h.tmp \ngit --work-tree=%~dp0 rev-parse --short HEAD >> %~dp0\\version.h.tmp\nif %ERRORLEVEL% neq 0 echo #define NO_GIT_COMMIT > %~dp0\\version.h.tmp\nfc %~dp0\\version.h.tmp %~dp0\\version.h\nif %ERRORLEVEL% neq 0 copy /Y %~dp0\\version.h.tmp %~dp0\\version.h\ndel %~dp0\\version.h.tmp\n"
  },
  {
    "path": "Player.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.13.35913.81 d17.13\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Player\", \"Player\\Player.vcxproj\", \"{C90196CD-7354-4ED4-BFC0-E51A7E1CBE3C}\"\n\tProjectSection(ProjectDependencies) = postProject\n\t\t{3013C140-DDFC-4BF4-9091-0C4131A0D2A6} = {3013C140-DDFC-4BF4-9091-0C4131A0D2A6}\n\t\t{3DE6C2D2-FDFC-4745-8282-981DF7561405} = {3DE6C2D2-FDFC-4745-8282-981DF7561405}\n\tEndProjectSection\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"video\", \"video\\video.vcxproj\", \"{3013C140-DDFC-4BF4-9091-0C4131A0D2A6}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{C9B5174D-7410-40E3-8962-76AD82A10E70}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"networking\", \"networking\\networking.vcxproj\", \"{3DE6C2D2-FDFC-4745-8282-981DF7561405}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"HttpDownload\", \"HttpDownload\\HttpDownload.vcxproj\", \"{A4113679-4736-494B-B8D2-3C35B34E5491}\"\nEndProject\nProject(\"{54435603-DBB4-11D2-8724-00A0C9A8B90C}\") = \"Setup\", \"Setup\\Setup.vdproj\", \"{72C57644-86FB-4587-9EE5-092F360D146C}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Dlls\", \"Dlls\\Dlls.csproj\", \"{BC1BC9F1-893D-4715-818A-F37F74EB5710}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"audio\", \"audio\\audio.vcxproj\", \"{8B955995-B5EC-41F0-940A-48A6F17BCBB8}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"Anime4KCPPCore\", \"Anime4KCPPCore.vcxproj\", \"{632353E4-4856-38F9-9E74-ED41BD99D7E5}\"\nEndProject\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"ToUTF8\", \"ToUTF8\\ToUTF8.vcxproj\", \"{F082EF32-A1D0-48B9-9AF1-DC56178EDE92}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Win32 = Debug|Win32\n\t\tDebug|x64 = Debug|x64\n\t\tRelease|Win32 = Release|Win32\n\t\tRelease|x64 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{C90196CD-7354-4ED4-BFC0-E51A7E1CBE3C}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{C90196CD-7354-4ED4-BFC0-E51A7E1CBE3C}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{C90196CD-7354-4ED4-BFC0-E51A7E1CBE3C}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{C90196CD-7354-4ED4-BFC0-E51A7E1CBE3C}.Debug|x64.Build.0 = Debug|x64\n\t\t{C90196CD-7354-4ED4-BFC0-E51A7E1CBE3C}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{C90196CD-7354-4ED4-BFC0-E51A7E1CBE3C}.Release|Win32.Build.0 = Release|Win32\n\t\t{C90196CD-7354-4ED4-BFC0-E51A7E1CBE3C}.Release|x64.ActiveCfg = Release|x64\n\t\t{C90196CD-7354-4ED4-BFC0-E51A7E1CBE3C}.Release|x64.Build.0 = Release|x64\n\t\t{3013C140-DDFC-4BF4-9091-0C4131A0D2A6}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{3013C140-DDFC-4BF4-9091-0C4131A0D2A6}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{3013C140-DDFC-4BF4-9091-0C4131A0D2A6}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{3013C140-DDFC-4BF4-9091-0C4131A0D2A6}.Debug|x64.Build.0 = Debug|x64\n\t\t{3013C140-DDFC-4BF4-9091-0C4131A0D2A6}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{3013C140-DDFC-4BF4-9091-0C4131A0D2A6}.Release|Win32.Build.0 = Release|Win32\n\t\t{3013C140-DDFC-4BF4-9091-0C4131A0D2A6}.Release|x64.ActiveCfg = Release|x64\n\t\t{3013C140-DDFC-4BF4-9091-0C4131A0D2A6}.Release|x64.Build.0 = Release|x64\n\t\t{3DE6C2D2-FDFC-4745-8282-981DF7561405}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{3DE6C2D2-FDFC-4745-8282-981DF7561405}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{3DE6C2D2-FDFC-4745-8282-981DF7561405}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{3DE6C2D2-FDFC-4745-8282-981DF7561405}.Debug|x64.Build.0 = Debug|x64\n\t\t{3DE6C2D2-FDFC-4745-8282-981DF7561405}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{3DE6C2D2-FDFC-4745-8282-981DF7561405}.Release|Win32.Build.0 = Release|Win32\n\t\t{3DE6C2D2-FDFC-4745-8282-981DF7561405}.Release|x64.ActiveCfg = Release|x64\n\t\t{3DE6C2D2-FDFC-4745-8282-981DF7561405}.Release|x64.Build.0 = Release|x64\n\t\t{A4113679-4736-494B-B8D2-3C35B34E5491}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{A4113679-4736-494B-B8D2-3C35B34E5491}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{A4113679-4736-494B-B8D2-3C35B34E5491}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{A4113679-4736-494B-B8D2-3C35B34E5491}.Debug|x64.Build.0 = Debug|x64\n\t\t{A4113679-4736-494B-B8D2-3C35B34E5491}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{A4113679-4736-494B-B8D2-3C35B34E5491}.Release|Win32.Build.0 = Release|Win32\n\t\t{A4113679-4736-494B-B8D2-3C35B34E5491}.Release|x64.ActiveCfg = Release|x64\n\t\t{A4113679-4736-494B-B8D2-3C35B34E5491}.Release|x64.Build.0 = Release|x64\n\t\t{72C57644-86FB-4587-9EE5-092F360D146C}.Debug|Win32.ActiveCfg = Debug\n\t\t{72C57644-86FB-4587-9EE5-092F360D146C}.Debug|x64.ActiveCfg = Debug\n\t\t{72C57644-86FB-4587-9EE5-092F360D146C}.Release|Win32.ActiveCfg = Release\n\t\t{72C57644-86FB-4587-9EE5-092F360D146C}.Release|x64.ActiveCfg = Release\n\t\t{BC1BC9F1-893D-4715-818A-F37F74EB5710}.Debug|Win32.ActiveCfg = Debug|Any CPU\n\t\t{BC1BC9F1-893D-4715-818A-F37F74EB5710}.Debug|Win32.Build.0 = Debug|Any CPU\n\t\t{BC1BC9F1-893D-4715-818A-F37F74EB5710}.Debug|x64.ActiveCfg = Debug|Any CPU\n\t\t{BC1BC9F1-893D-4715-818A-F37F74EB5710}.Debug|x64.Build.0 = Debug|Any CPU\n\t\t{BC1BC9F1-893D-4715-818A-F37F74EB5710}.Release|Win32.ActiveCfg = Release|Any CPU\n\t\t{BC1BC9F1-893D-4715-818A-F37F74EB5710}.Release|Win32.Build.0 = Release|Any CPU\n\t\t{BC1BC9F1-893D-4715-818A-F37F74EB5710}.Release|x64.ActiveCfg = Release|Any CPU\n\t\t{BC1BC9F1-893D-4715-818A-F37F74EB5710}.Release|x64.Build.0 = Release|Any CPU\n\t\t{8B955995-B5EC-41F0-940A-48A6F17BCBB8}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{8B955995-B5EC-41F0-940A-48A6F17BCBB8}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{8B955995-B5EC-41F0-940A-48A6F17BCBB8}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{8B955995-B5EC-41F0-940A-48A6F17BCBB8}.Debug|x64.Build.0 = Debug|x64\n\t\t{8B955995-B5EC-41F0-940A-48A6F17BCBB8}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{8B955995-B5EC-41F0-940A-48A6F17BCBB8}.Release|Win32.Build.0 = Release|Win32\n\t\t{8B955995-B5EC-41F0-940A-48A6F17BCBB8}.Release|x64.ActiveCfg = Release|x64\n\t\t{8B955995-B5EC-41F0-940A-48A6F17BCBB8}.Release|x64.Build.0 = Release|x64\n\t\t{632353E4-4856-38F9-9E74-ED41BD99D7E5}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{632353E4-4856-38F9-9E74-ED41BD99D7E5}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{632353E4-4856-38F9-9E74-ED41BD99D7E5}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{632353E4-4856-38F9-9E74-ED41BD99D7E5}.Debug|x64.Build.0 = Debug|x64\n\t\t{632353E4-4856-38F9-9E74-ED41BD99D7E5}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{632353E4-4856-38F9-9E74-ED41BD99D7E5}.Release|Win32.Build.0 = Release|Win32\n\t\t{632353E4-4856-38F9-9E74-ED41BD99D7E5}.Release|x64.ActiveCfg = Release|x64\n\t\t{632353E4-4856-38F9-9E74-ED41BD99D7E5}.Release|x64.Build.0 = Release|x64\n\t\t{F082EF32-A1D0-48B9-9AF1-DC56178EDE92}.Debug|Win32.ActiveCfg = Debug|Win32\n\t\t{F082EF32-A1D0-48B9-9AF1-DC56178EDE92}.Debug|Win32.Build.0 = Debug|Win32\n\t\t{F082EF32-A1D0-48B9-9AF1-DC56178EDE92}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{F082EF32-A1D0-48B9-9AF1-DC56178EDE92}.Debug|x64.Build.0 = Debug|x64\n\t\t{F082EF32-A1D0-48B9-9AF1-DC56178EDE92}.Release|Win32.ActiveCfg = Release|Win32\n\t\t{F082EF32-A1D0-48B9-9AF1-DC56178EDE92}.Release|Win32.Build.0 = Release|Win32\n\t\t{F082EF32-A1D0-48B9-9AF1-DC56178EDE92}.Release|x64.ActiveCfg = Release|x64\n\t\t{F082EF32-A1D0-48B9-9AF1-DC56178EDE92}.Release|x64.Build.0 = Release|x64\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {75699A84-B7AB-4C3D-86E3-5E2370B5D57B}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "QtPlayer/.gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n"
  },
  {
    "path": "QtPlayer/.gitignore",
    "content": "# C++ objects and libs\n*.slo\n*.lo\n*.o\n*.a\n*.la\n*.lai\n*.so\n*.dll\n*.dylib\n\n# Qt-es\nobject_script.*.Release\nobject_script.*.Debug\n*_plugin_import.cpp\n/.qmake.cache\n/.qmake.stash\n*.pro.user\n*.pro.user.*\n*.qbs.user\n*.qbs.user.*\n*.moc\nmoc_*.cpp\nmoc_*.h\nqrc_*.cpp\nui_*.h\n*.qmlc\n*.jsc\nMakefile*\n*build-*\n\n# Qt unit tests\ntarget_wrapper.*\n\n# QtCreator\n*.autosave\n\n# QtCreator Qml\n*.qmlproject.user\n*.qmlproject.user.*\n\n# QtCreator CMake\nCMakeLists.txt.user*\nCMake*Presets.json\nCMakeSettings.json\n"
  },
  {
    "path": "QtPlayer/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.5)\n\nproject(QtPlayer LANGUAGES CXX)\n\noption(DEVELOPER_OPENGL \"Enables opengl display\" ON)\n\nset(CMAKE_INCLUDE_CURRENT_DIR ON)\n\nset(CMAKE_AUTOUIC ON)\nset(CMAKE_AUTOMOC ON)\nset(CMAKE_AUTORCC ON)\n\nset(CMAKE_CXX_STANDARD 17)\nset(CMAKE_CXX_STANDARD_REQUIRED ON)\n\nif(MSVC)\n  add_definitions(-D_WIN32_WINNT=0x0602)\nendif()\n\nif(DEVELOPER_OPENGL)\n        add_definitions(-DDEVELOPER_OPENGL)\nendif(DEVELOPER_OPENGL)\n\nadd_definitions(-DBOOST_LOG_DYN_LINK)\n\n# QtCreator supports the following variables for Android, which are identical to qmake Android variables.\n# Check http://doc.qt.io/qt-5/deployment-android.html for more information.\n# They need to be set before the find_package(Qt5 ...) call.\n\n#if(ANDROID)\n#    set(ANDROID_PACKAGE_SOURCE_DIR \"${CMAKE_CURRENT_SOURCE_DIR}/android\")\n#    if (ANDROID_ABI STREQUAL \"armeabi-v7a\")\n#        set(ANDROID_EXTRA_LIBS\n#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so\n#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)\n#    endif()\n#endif()\n\nfind_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)\nfind_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)\n\nfind_package(Boost REQUIRED thread log)\n\nfind_package(portaudio CONFIG)\nif(NOT PORTAUDIO_FOUND)\n    find_path(PORTAUDIO_INCLUDE_DIR\n          NAMES portaudio.h\n          DOC \"The PortAudio include directory\"\n    )\n    find_library(PORTAUDIO_LIBRARY\n             NAMES portaudio\n             DOC \"The PortAudio library\"\n    )\n    include(FindPackageHandleStandardArgs)\n    find_package_handle_standard_args(PortAudio\n        REQUIRED_VARS PORTAUDIO_LIBRARY PORTAUDIO_INCLUDE_DIR\n    )\n    if(PORTAUDIO_FOUND)\n        set(PORTAUDIO_LIBRARIES ${PORTAUDIO_LIBRARY})\n        set(PORTAUDIO_INCLUDE_DIRS ${PORTAUDIO_INCLUDE_DIR})\n    endif()\nendif()\n\n\nfind_path(AVCODEC_INCLUDE_DIR libavcodec/avcodec.h)\n\nif (AVCODEC_INCLUDE_DIR)\n\n  find_library(AVCODEC_LIBRARY avcodec)\n\n  find_path(AVFORMAT_INCLUDE_DIR libavformat/avformat.h)\n  find_library(AVFORMAT_LIBRARY avformat)\n\n  find_path(AVUTIL_INCLUDE_DIR libavutil/avutil.h)\n  find_library(AVUTIL_LIBRARY avutil)\n\n  find_path(AVDEVICE_INCLUDE_DIR libavdevice/avdevice.h)\n  find_library(AVDEVICE_LIBRARY avdevice)\n\n  find_path(SWSCALE_INCLUDE_DIR libswscale/swscale.h)\n  find_library(SWSCALE_LIBRARY swscale)\n\n  find_path(SWRESAMPLE_INCLUDE_DIR libswresample/swresample.h)\n  find_library(SWRESAMPLE_LIBRARY swresample)\n\nelse()\n  find_package(PkgConfig REQUIRED)\n  pkg_check_modules(LIBAV REQUIRED IMPORTED_TARGET\n    libavdevice\n    libavfilter\n    libavformat\n    libavcodec\n    libswresample\n    libswscale\n    libavutil\n  )\nendif()\n\nset(SOURCES\n    customdockwidget.cpp\n    customdockwidget.h\n    ffmpegdecoder.cpp\n    ffmpegdecoder.h\n    main.cpp\n    mainwindow.cpp\n    mainwindow.h\n    mainwindow.ui\n    mousehoverbutton.cpp\n    mousehoverbutton.h\n    opengldisplay.cpp\n    opengldisplay.h   \n    portaudioplayer.cpp\n    portaudioplayer.h\n    videocontrol.cpp\n    videocontrol.h\n    videocontrol.ui\n    videodisplay.cpp\n    videodisplay.h\n    videoplayer.cpp\n    videoplayer.h\n    videoplayerwidget.cpp\n    videoplayerwidget.h\n    videoprogressbar.cpp\n    videoprogressbar.h\n    videowidget.cpp\n    videowidget.h\n    volumeprogressbar.cpp\n    volumeprogressbar.h\n    widgetdisplay.cpp\n    widgetdisplay.h)\n\nif(WIN32)\nadd_executable(QtPlayer WIN32 ${SOURCES} ${CMAKE_SOURCE_DIR}/resources/resources.qrc)\nelseif(APPLE)\nadd_executable(QtPlayer MACOSX_BUNDLE ${SOURCES} ${CMAKE_SOURCE_DIR}/resources/resources.qrc)\nelse()\nadd_executable(QtPlayer ${SOURCES} ${CMAKE_SOURCE_DIR}/resources/resources.qrc)\nendif()\n\n\nfile(GLOB VIDEO_SRCS ../video/*.cpp)\nadd_library(video STATIC ${VIDEO_SRCS})\n\ntarget_include_directories(video PRIVATE ../video)\n\nif (AVCODEC_INCLUDE_DIR)\n    target_include_directories(video PRIVATE\n        ${AVCODEC_INCLUDE_DIR}\n        ${AVFORMAT_INCLUDE_DIR}\n        ${AVUTIL_INCLUDE_DIR}\n        ${AVDEVICE_INCLUDE_DIR}\n        ${SWSCALE_INCLUDE_DIR}\n        ${SWRESAMPLE_INCLUDE_DIR}\n    )\nendif()\n\n\ntarget_link_libraries(video ${Boost_LIBRARIES})\nif (AVCODEC_INCLUDE_DIR)\n    target_link_libraries(video \n        ${AVCODEC_LIBRARY}\n        ${AVFORMAT_LIBRARY}\n        ${AVUTIL_LIBRARY}\n        ${AVDEVICE_LIBRARY}\n        ${SWSCALE_LIBRARY}\n        ${SWRESAMPLE_LIBRARY}\n        )\nelse()\n    target_link_libraries(video \n        PkgConfig::LIBAV\n        )\nendif()\n\n#file(GLOB AUDIO_SRCS ../audio/*.cpp)\n#add_library(audio STATIC ${AUDIO_SRCS})\n#target_include_directories(audio PRIVATE ../audio)\n#target_link_libraries(audio)\n\ntarget_include_directories(QtPlayer PRIVATE ${Boost_INCLUDE_DIRS} ${PORTAUDIO_INCLUDE_DIRS})\n\ntarget_link_libraries(QtPlayer PRIVATE Qt${QT_VERSION_MAJOR}::Widgets video ${PORTAUDIO_LIBRARIES})\nif(WIN32)\n  target_link_libraries(QtPlayer PRIVATE ws2_32)\nendif()\n"
  },
  {
    "path": "QtPlayer/customdockwidget.cpp",
    "content": "#include \"customdockwidget.h\"\n#include \"mainwindow.h\"\n#include \"videoplayerwidget.h\"\n#include \"videowidget.h\"\n\n#include <QCloseEvent>\n#include <QWidget>\n#include <QEvent>\n\nCustomDockWidget::CustomDockWidget(QWidget* widget) : QWidget(widget) \n{\n}\n\nvoid CustomDockWidget::setDisplayForFullscreen(VideoDisplay* display)\n{\n\tQ_ASSERT(display != nullptr);\n    m_display = dynamic_cast<VideoWidget*>(display);\n}\n\nvoid CustomDockWidget::closeEvent(QCloseEvent* event)\n{\n\tevent->ignore();\n}\n\nvoid CustomDockWidget::keyPressEvent(QKeyEvent* event)\n{\n\t// Player fullscreen in\n\tif ((event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) && (event->modifiers() & Qt::AltModifier))\n\t{\n\t\tsetVisibilityState(FullScreen);\n\t\tevent->ignore();\n\t}\n    QWidget::keyPressEvent(event);\n}\n\nvoid CustomDockWidget::setVisibilityState(VisibilityState state)\n{\n\tif (state == m_state)\n\t{\n\t\treturn;\n\t}\n\n\tswitch (state)\n\t{\n\tcase ShownDocked:\n\t{\n\t\tthis->setVisible(true);\n\t}\n\tbreak;\n\tcase FullScreen:\n\t{\n\t\tbool prevIsFullScreen = m_display->isFullScreen();\n\t\tm_display->fullScreen(!prevIsFullScreen);\n\t\tif (m_display->isFullScreen() == prevIsFullScreen)\n\t\t{\n\t\t\treturn;\n\t\t}\n\t\t// emit enterFullscreen(true);\n\t}\n\tbreak;\n\t}\n\tm_prevState = m_state;\n\tm_state = state;\n}\n\nvoid CustomDockWidget::onLeaveFullScreen()\n{\n\tif (m_display->isFullScreen())\n\t{\n\t\tm_display->fullScreen(false);\n\t}\n\tsetVisibilityState(m_prevState);\n}\n"
  },
  {
    "path": "QtPlayer/customdockwidget.h",
    "content": "#pragma once\n\n#include <QWidget>\n\nclass VideoDisplay;\nclass VideoWidget;\n\n\nclass CustomDockWidget : public QWidget\n{\n\tQ_OBJECT\npublic:\n\tCustomDockWidget(QWidget* widget = nullptr);\n\tvoid setDisplayForFullscreen(VideoDisplay* display);\n\n\tenum VisibilityState\n\t{\n\t\tShownDocked = 0,\n\t\tFullScreen\n\t};\n\n\tvoid setVisibilityState(VisibilityState state);\n\tVisibilityState currentState() const { return m_state; }\n\tVisibilityState previousState() const { return m_prevState; }\n\nprotected:\n\tvoid closeEvent(QCloseEvent* event) override;\n\tvoid keyPressEvent(QKeyEvent* event) override;\n\nsignals:\n\tbool enterFullscreen(bool f);\n\npublic slots:\n\tvoid onLeaveFullScreen();\n\nprivate:\n\tVisibilityState m_state{ShownDocked};\n\tVisibilityState m_prevState{ShownDocked};\n    VideoWidget* m_display{};\n};\n"
  },
  {
    "path": "QtPlayer/ffmpegdecoder.cpp",
    "content": "#include \"ffmpegdecoder.h\"\n\n//#include \"../audio/AudioPlayerWasapi.h\"\n\n#include \"portaudioplayer.h\"\n\n#include \"videodisplay.h\"\n\nFFmpegDecoderWrapper::FFmpegDecoderWrapper()\n    : m_frameDecoder(\n        GetFrameDecoder(std::make_unique<PortAudioPlayer>()))\n{\n    m_frameDecoder->setDecoderListener(this);\n}\n\nFFmpegDecoderWrapper::~FFmpegDecoderWrapper() = default;\n\nvoid FFmpegDecoderWrapper::setFrameListener(VideoDisplay* listener)\n{\n    m_frameDecoder->setFrameListener(listener);\n    if (listener != nullptr) {\n        listener->setDecoderObject(this);\n}\n}\n\nbool FFmpegDecoderWrapper::openFile(const QString& file)\n{\n    return m_frameDecoder->openUrls({file.toStdString()});\n}\n"
  },
  {
    "path": "QtPlayer/ffmpegdecoder.h",
    "content": "#pragma once\n\n#include \"../video/decoderinterface.h\"\n\n#include <QObject>\n\n#include <QString>\n\n#include <memory>\n\nclass VideoDisplay;\n\nclass FFmpegDecoderWrapper : public QObject, public FrameDecoderListener\n{\n\tQ_OBJECT\n\npublic:\n    FFmpegDecoderWrapper();\n    ~FFmpegDecoderWrapper() override;\n\n    FFmpegDecoderWrapper(const FFmpegDecoderWrapper&) = delete;\n    FFmpegDecoderWrapper& operator=(const FFmpegDecoderWrapper&) = delete;\n\n    void setFrameListener(VideoDisplay* listener);\n\n    bool openFile(const QString& file);\n    void play(bool isPaused = false) { m_frameDecoder->play(); }\n    bool pauseResume() { return m_frameDecoder->pauseResume(); }\n    void close(bool isBlocking = true) { m_frameDecoder->close(); }\n    void setVolume(double volume)\n    {\n        m_frameDecoder->setVolume(volume);\n        emit volumeChanged(volume);\n    }\n    bool seekByPercent(float percent) { return m_frameDecoder->seekByPercent(percent); }\n\n    double volume() const { return m_frameDecoder->volume(); }\n    bool isPlaying() const { return m_frameDecoder->isPlaying(); }\n\n    void finishedDisplayingFrame(unsigned int generation) { m_frameDecoder->finishedDisplayingFrame(generation); }\n\n    IFrameDecoder* getFrameDecoder() const { return m_frameDecoder.get(); }\n\n    void playingFinished() override { emit onPlayingFinished(); }\n    void changedFramePosition(\n        long long start, long long frame, long long total) override\n    {\n        emit onChangedFramePosition(frame - start, total - start);\n    }\n\nsignals:\n    void onPlayingFinished();\n    void onChangedFramePosition(qint64, qint64);\n    void volumeChanged(double /*unused*/) override;\n\nprivate:\n    std::unique_ptr<IFrameDecoder> m_frameDecoder;\n};\n"
  },
  {
    "path": "QtPlayer/main.cpp",
    "content": "#include \"mainwindow.h\"\n\n#include <QApplication>\n\n#include <boost/log/sinks/debug_output_backend.hpp>\n#include <boost/log/sinks/text_ostream_backend.hpp>\n#include <boost/log/sinks/sync_frontend.hpp>\n#include <boost/log/core/core.hpp>\n#include <boost/log/utility/setup/common_attributes.hpp>\n\n#include <boost/log/expressions.hpp>\n\n#include <boost/log/trivial.hpp>\n\n#include <boost/log/support/date_time.hpp>\n\nstatic void init_logging()\n{\n    namespace expr = boost::log::expressions;\n\n    boost::log::add_common_attributes();\n\n    auto core = boost::log::core::get();\n\n#ifdef Q_OS_WIN\n    // Create the sink. The backend requires synchronization in the frontend.\n    auto sink(boost::make_shared<boost::log::sinks::synchronous_sink<boost::log::sinks::debug_output_backend>>());\n#else\n    auto sink = boost::make_shared<boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend >>();\n#endif\n\n    sink->set_formatter(expr::stream\n        //<< '[' << expr::format_date_time< boost::posix_time::ptime >(\"TimeStamp\", \"%H:%M:%S.%f\") << ']'\n        << expr::if_(expr::has_attr(\"Severity\"))\n        [\n            expr::stream << '[' << expr::attr< boost::log::trivial::severity_level >(\"Severity\") << ']'\n        ]\n    << expr::if_(expr::has_attr(\"Channel\"))\n        [\n            expr::stream << '[' << expr::attr< std::string >(\"Channel\") << ']'\n        ]\n    << expr::smessage << '\\n');\n\n    // Set the special filter to the frontend\n    // in order to skip the sink when no debugger is available\n    //sink->set_filter(expr::is_debugger_present());\n\n    core->add_sink(sink);\n}\n\nint main(int argc, char *argv[])\n{\n    init_logging();\n\n    QApplication a(argc, argv);\n    MainWindow w;\n    w.show();\n    return QApplication::exec();\n}\n"
  },
  {
    "path": "QtPlayer/mainwindow.cpp",
    "content": "#include \"mainwindow.h\"\n#include \"./ui_mainwindow.h\"\n\n#include \"videowidget.h\"\n\n#include <QFileDialog>\n#include <QInputDialog>\n\nMainWindow* getMainWindow()\n{\n    for (QWidget* widget : QApplication::topLevelWidgets()) {\n        if (auto *mainWindow = qobject_cast<MainWindow*>(widget)) {\n            return mainWindow;\n        }\n    }\n    return nullptr;\n}\n\n\nMainWindow::MainWindow(QWidget *parent)\n    : QMainWindow(parent)\n    , ui(new Ui::MainWindow)\n{\n    ui->setupUi(this);\n\n    auto m_player = ui->videoPlayerWidget;\n\n    m_player->setProgressbar(ui->videoProgress);\n\n    ui->dockWidget->installEventFilter(m_player);\n    ui->dockWidget->setDisplayForFullscreen(m_player->getCurrentDisplay());\n\n    setCentralWidget(ui->dockWidget);\n\n    connect(m_player->videoWidget(), &VideoWidget::leaveFullScreen, ui->dockWidget, &CustomDockWidget::onLeaveFullScreen);\n\n    connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::onFileOpen);\n    connect(ui->actionOpenUrl, &QAction::triggered, this, &MainWindow::onUrlOpen);\n}\n\nMainWindow::~MainWindow()\n{\n    delete ui;\n}\n\nCustomDockWidget* MainWindow::dockWidget()\n{\n    return ui->dockWidget;\n}\n\nQWidget* MainWindow::videoControlWidget()\n{\n    return ui->videoControl;\n}\n\nVideoPlayerWidget* MainWindow::getPlayer()\n{\n    return ui->videoPlayerWidget;\n}\n\nvoid MainWindow::onFileOpen()\n{\n    auto fileName = QFileDialog::getOpenFileName(\n                 this,\n                 tr(\"Open Video File\"));\n    if (!fileName.isEmpty())\n    {\n        getPlayer()->playFile(fileName);\n    }\n}\n\nvoid MainWindow::onUrlOpen()\n{\n    QInputDialog dialog(this);\n    dialog.setWindowTitle(tr(\"Open URL\"));\n    dialog.setLabelText(tr(\"Url to open:\"));\n    if (dialog.exec() == QDialog::Accepted)\n    {\n        QString fileName = dialog.textValue();\n        if (!fileName.isEmpty())\n        {\n            getPlayer()->playFile(fileName);\n        }\n    }\n}\n"
  },
  {
    "path": "QtPlayer/mainwindow.h",
    "content": "#pragma once\n\n#include <QMainWindow>\n\nQT_BEGIN_NAMESPACE\nnamespace Ui { class MainWindow; }\nQT_END_NAMESPACE\n\nclass CustomDockWidget;\nclass VideoPlayerWidget;\n\nclass MainWindow : public QMainWindow\n{\n    Q_OBJECT\n\npublic:\n    MainWindow(QWidget *parent = nullptr);\n    ~MainWindow() override;\n\n\n    CustomDockWidget* dockWidget();\n    QWidget* videoControlWidget();\n    VideoPlayerWidget* getPlayer();\n\nprivate:\n    void onFileOpen();\n    void onUrlOpen();\n\nprivate:\n    Ui::MainWindow *ui;\n};\n\nMainWindow* getMainWindow();\n"
  },
  {
    "path": "QtPlayer/mainwindow.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>MainWindow</class>\n <widget class=\"QMainWindow\" name=\"MainWindow\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>803</width>\n    <height>604</height>\n   </rect>\n  </property>\n  <property name=\"windowTitle\">\n   <string>MainWindow</string>\n  </property>\n  <widget class=\"CustomDockWidget\" name=\"dockWidget\">\n   <property name=\"sizePolicy\">\n    <sizepolicy hsizetype=\"Ignored\" vsizetype=\"Preferred\">\n     <horstretch>0</horstretch>\n     <verstretch>0</verstretch>\n    </sizepolicy>\n   </property>\n   <property name=\"maximumSize\">\n    <size>\n     <width>16777215</width>\n     <height>16777215</height>\n    </size>\n   </property>\n   <property name=\"styleSheet\">\n    <string notr=\"true\"/>\n   </property>\n   <layout class=\"QVBoxLayout\" name=\"verticalLayout_3\">\n    <property name=\"spacing\">\n     <number>0</number>\n    </property>\n    <property name=\"margin\">\n     <number>0</number>\n    </property>\n    <item>\n     <widget class=\"VideoPlayerWidget\" name=\"videoPlayerWidget\">\n      <property name=\"focusPolicy\">\n       <enum>Qt::StrongFocus</enum>\n      </property>\n      <property name=\"styleSheet\">\n       <string notr=\"true\"/>\n      </property>\n      <property name=\"frameShape\">\n       <enum>QFrame::NoFrame</enum>\n      </property>\n      <property name=\"frameShadow\">\n       <enum>QFrame::Plain</enum>\n      </property>\n      <property name=\"lineWidth\">\n       <number>0</number>\n      </property>\n      <widget class=\"VideoControl\" name=\"videoControl\" native=\"true\">\n       <property name=\"geometry\">\n        <rect>\n         <x>0</x>\n         <y>238</y>\n         <width>230</width>\n         <height>16</height>\n        </rect>\n       </property>\n      </widget>\n      <widget class=\"VideoProgressBar\" name=\"videoProgress\">\n       <property name=\"geometry\">\n        <rect>\n         <x>0</x>\n         <y>220</y>\n         <width>229</width>\n         <height>18</height>\n        </rect>\n       </property>\n       <property name=\"maximumSize\">\n        <size>\n         <width>16777215</width>\n         <height>18</height>\n        </size>\n       </property>\n       <property name=\"styleSheet\">\n        <string notr=\"true\"/>\n       </property>\n       <property name=\"maximum\">\n        <number>10000</number>\n       </property>\n       <property name=\"value\">\n        <number>0</number>\n       </property>\n       <property name=\"textVisible\">\n        <bool>false</bool>\n       </property>\n      </widget>\n     </widget>\n    </item>\n   </layout>\n  </widget>\n  <widget class=\"QMenuBar\" name=\"menubar\">\n   <property name=\"geometry\">\n    <rect>\n     <x>0</x>\n     <y>0</y>\n     <width>803</width>\n     <height>21</height>\n    </rect>\n   </property>\n   <widget class=\"QMenu\" name=\"menuFile\">\n    <property name=\"title\">\n     <string>File</string>\n    </property>\n    <addaction name=\"actionOpen\"/>\n    <addaction name=\"actionOpenUrl\"/>\n   </widget>\n   <addaction name=\"menuFile\"/>\n  </widget>\n  <widget class=\"QStatusBar\" name=\"statusbar\"/>\n  <action name=\"actionOpen\">\n   <property name=\"text\">\n    <string>Open</string>\n   </property>\n  </action>\n  <action name=\"actionOpenUrl\">\n   <property name=\"text\">\n    <string>Open URL</string>\n   </property>\n  </action>\n </widget>\n<customwidgets>\n <customwidget>\n  <class>VideoControl</class>\n  <extends>QWidget</extends>\n  <header>videocontrol.h</header>\n  <container>1</container>\n </customwidget>\n <customwidget>\n  <class>CustomDockWidget</class>\n  <extends>QWidget</extends>\n  <header>customdockwidget.h</header>\n  <container>1</container>\n </customwidget>\n <customwidget>\n  <class>VideoPlayerWidget</class>\n  <extends>QFrame</extends>\n  <header>videoplayerwidget.h</header>\n  <container>1</container>\n </customwidget>\n <customwidget>\n  <class>VideoProgressBar</class>\n  <extends>QProgressBar</extends>\n  <header>videoprogressbar.h</header>\n </customwidget>\n</customwidgets>\n <resources>\n  <include location=\"resources/resources.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "QtPlayer/mousehoverbutton.cpp",
    "content": "#include \"mousehoverbutton.h\"\n#include <QMouseEvent>\n\nMouseHoverButton::MouseHoverButton(QWidget* parent) : QToolButton(parent)\n{\n}\n\n\nMouseHoverButton::~MouseHoverButton() = default;\n\nvoid MouseHoverButton::mousePressEvent(QMouseEvent* event)\n{\n\tif (m_defIcon.isNull())\n\t{\n\t\tm_defIcon = icon();\n\t\tQList<QSize> normalOnSizes = m_defIcon.availableSizes(QIcon::Normal, QIcon::On);\n\t\tif (!normalOnSizes.empty())\n\t\t{\n\t\t\t// use normal/on image as pushed one\n\t\t\tm_pushedIcon = m_defIcon.pixmap(*normalOnSizes.begin(), QIcon::Normal, QIcon::On);\n\t\t}\n\t}\n\tQToolButton::mousePressEvent(event);\n\tif (event->buttons() & Qt::LeftButton)\n\t{\n\t\tsetIcon(m_pushedIcon);\n\t}\n}\n\nvoid MouseHoverButton::mouseReleaseEvent(QMouseEvent* event)\n{\n\tif (event->button() == Qt::LeftButton)\n\t{\n\t\tsetIcon(m_defIcon);\n\t}\n\tQToolButton::mouseReleaseEvent(event);\n}\n\nvoid MouseHoverButton::keyReleaseEvent(QKeyEvent* e)\n{\n\tQ_UNUSED(e)\n\t// do nothing so button won't process key events\n}\n\nvoid MouseHoverButton::paintEvent(QPaintEvent* event)\n{\n\tbool isButtonDown = isDown();\n\tsetDown(false);\n\tQToolButton::paintEvent(event);\n\tsetDown(isButtonDown);\n}\n"
  },
  {
    "path": "QtPlayer/mousehoverbutton.h",
    "content": "#pragma once\n\n#include <QToolButton>\n#include <QIcon>\n\n/*\n\tSince Qt tool button pushes icon's image for pressed state, we have own implementation.\n\tTo get it properly worked next images should be assigned to\n\tnext button states programmatically or in the Qt designer:\n\tNormal Off - default image\n\tNormal On - clicked image\n\tDisabled Off - disabled image\n\tDisabled On - disabled image\n\tActive Off - hover image\n\tActive On - hover image\n\tSelected Off - default image\n\tSelected On - default image\n*/\nclass MouseHoverButton : public QToolButton\n{\n\tQ_OBJECT\npublic:\n\tMouseHoverButton(QWidget* parent);\n\t~MouseHoverButton() override;\nprotected:\n\tvoid mousePressEvent(QMouseEvent* event) override;\n\tvoid mouseReleaseEvent(QMouseEvent* event) override;\n\tvoid keyReleaseEvent(QKeyEvent* e) override;\n\tvoid paintEvent(QPaintEvent* event) override;\nprivate:\n\tQIcon m_defIcon;\n\tQIcon m_pushedIcon;\n};\n"
  },
  {
    "path": "QtPlayer/opengldisplay.cpp",
    "content": "#include \"opengldisplay.h\"\n\n// https://github.com/MasterAler/SampleYUVRenderer\n\n#include <QOpenGLShader>\n#include <QOpenGLTexture>\n#include <QCoreApplication>\n#include <QResizeEvent>\n\n#include <algorithm>\n#include <atomic>\n#include <mutex>\n\n\nenum {\nPROGRAM_VERTEX_ATTRIBUTE  = 0,\nPROGRAM_TEXCOORD_ATTRIBUTE = 1,\n\nATTRIB_VERTEX = 0,\nATTRIB_TEXTURE = 1,\n};\n\nstruct OpenGLDisplay::OpenGLDisplayImpl\n{\n    GLvoid*                 mBufYuv{nullptr};\n    unsigned int mFrameSize{0};\n\n    QOpenGLShader*          mVShader;\n    QOpenGLShader*          mFShader;\n    QOpenGLShaderProgram*   mShaderProgram;\n\n    QOpenGLTexture*         mTextureY;\n    QOpenGLTexture*         mTextureU;\n    QOpenGLTexture*         mTextureV;\n\n    GLuint                  id_y, id_u, id_v;\n    int                     textureUniformY, textureUniformU, textureUniformV;\n    GLsizei                 mVideoW, mVideoH;\n\n    std::mutex m_mutex;\n\n    float m_aspectRatio{ 0.75F };\n\n    std::atomic_bool m_pendingUpdate = false;\n};\n\n/*************************************************************************/\n\nOpenGLDisplay::OpenGLDisplay(QWidget* parent)\n    : QOpenGLWidget(parent)\n    , impl(new OpenGLDisplayImpl())\n{\n    setAttribute(Qt::WA_OpaquePaintEvent, true);\n}\n\nOpenGLDisplay::~OpenGLDisplay()\n{\n    delete[] reinterpret_cast<unsigned char*>(impl->mBufYuv);\n}\n\nvoid OpenGLDisplay::InitDrawBuffer(unsigned bsize)\n{\n    if (impl->mFrameSize < bsize)\n    {\n        delete[] reinterpret_cast<unsigned char*>(impl->mBufYuv);\n        impl->mFrameSize = bsize;\n        impl->mBufYuv = new unsigned char[bsize];\n    }\n}\n\n//void OpenGLDisplay::DisplayVideoFrame(unsigned char *data, int frameWidth, int frameHeight)\n//{\n//    impl->mVideoW = frameWidth;\n//    impl->mVideoH = frameHeight;\n//    memcpy(impl->mBufYuv, data, impl->mFrameSize);\n//    update();\n//}\n\nvoid OpenGLDisplay::initializeGL()\n{\n    initializeOpenGLFunctions();\n\n    glEnable(GL_DEPTH_TEST);\n\n    /* Modern opengl rendering pipeline relies on shaders to handle incoming data.\n     *  Shader: is a small function written in OpenGL Shading Language (GLSL).\n     * GLSL is the language that makes up all OpenGL shaders.\n     * The syntax of the specific GLSL language requires the reader to find relevant information. */\n\n    // Initialize the vertex shader object\n    impl->mVShader = new QOpenGLShader(QOpenGLShader::Vertex, this);\n\n    //Vertex shader source\n    const char *vsrc = \"attribute vec4 vertexIn; \\\n        attribute vec2 textureIn; \\\n        varying vec2 textureOut;  \\\n        void main(void)           \\\n        {                         \\\n            gl_Position = vertexIn; \\\n            textureOut = textureIn; \\\n        }\";\n\n    //Compile the vertex shader program\n    bool bCompile = impl->mVShader->compileSourceCode(vsrc);\n    if(!bCompile)\n    {\n        throw OpenGlException();\n    }\n\n    // Initialize the fragment shader function yuv converted to rgb\n    impl->mFShader = new QOpenGLShader(QOpenGLShader::Fragment, this);\n\n    // Fragment shader source code\n\n    const char *fsrc = (context()->isOpenGLES())\n    ? \"precision mediump float; \\\n    varying vec2 textureOut; \\\n    uniform sampler2D tex_y; \\\n    uniform sampler2D tex_u; \\\n    uniform sampler2D tex_v; \\\n    void main(void) \\\n    { \\\n        vec3 yuv; \\\n        vec3 rgb; \\\n        yuv.x = texture2D(tex_y, textureOut).r; \\\n        yuv.y = texture2D(tex_u, textureOut).r - 0.5; \\\n        yuv.z = texture2D(tex_v, textureOut).r - 0.5; \\\n        rgb = mat3( 1,       1,         1, \\\n                    0,       -0.39465,  2.03211, \\\n                    1.13983, -0.58060,  0) * yuv; \\\n        gl_FragColor = vec4(rgb, 1); \\\n    }\"\n    : \"varying vec2 textureOut; \\\n    uniform sampler2D tex_y; \\\n    uniform sampler2D tex_u; \\\n    uniform sampler2D tex_v; \\\n    void main(void) \\\n    { \\\n        vec3 yuv; \\\n        vec3 rgb; \\\n        yuv.x = texture2D(tex_y, textureOut).r; \\\n        yuv.y = texture2D(tex_u, textureOut).r - 0.5; \\\n        yuv.z = texture2D(tex_v, textureOut).r - 0.5; \\\n        rgb = mat3( 1,       1,         1, \\\n                    0,       -0.39465,  2.03211, \\\n                    1.13983, -0.58060,  0) * yuv; \\\n        gl_FragColor = vec4(rgb, 1); \\\n    }\";\n\n    bCompile = impl->mFShader->compileSourceCode(fsrc);\n    if(!bCompile)\n    {\n        throw OpenGlException();\n    }\n    \n    // Create a shader program container\n    impl->mShaderProgram = new QOpenGLShaderProgram(this);\n    // Add the fragment shader to the program container\n    impl->mShaderProgram->addShader(impl->mFShader);\n    // Add a vertex shader to the program container\n    impl->mShaderProgram->addShader(impl->mVShader);\n    // Bind the property vertexIn to the specified location ATTRIB_VERTEX, this property\n    // has a declaration in the vertex shader source\n    impl->mShaderProgram->bindAttributeLocation(\"vertexIn\", ATTRIB_VERTEX);\n    // Bind the attribute textureIn to the specified location ATTRIB_TEXTURE, the attribute \n    // has a declaration in the vertex shader source\n    impl->mShaderProgram->bindAttributeLocation(\"textureIn\", ATTRIB_TEXTURE);\n    //Link all the shader programs added to\n    impl->mShaderProgram->link();\n    //activate all links\n    impl->mShaderProgram->bind();\n    // Read the position of the data variables tex_y, tex_u, tex_v in the shader, the declaration\n    // of these variables can be seen in \n    // fragment shader source \n    impl->textureUniformY = impl->mShaderProgram->uniformLocation(\"tex_y\");\n    impl->textureUniformU = impl->mShaderProgram->uniformLocation(\"tex_u\");\n    impl->textureUniformV = impl->mShaderProgram->uniformLocation(\"tex_v\");\n    \n    //Vertex matrix\n    static const GLfloat vertexVertices[] = {\n        -1.0F, -1.0F,\n         1.0F, -1.0F,\n         -1.0F, 1.0F,\n         1.0F, 1.0F,\n    };\n    \n    //Texture matrix\n    static const GLfloat textureVertices[] = {\n        0.0F,  1.0F,\n        1.0F,  1.0F,\n        0.0F,  0.0F,\n        1.0F,  0.0F,\n    };\n\n    // Set the value of the vertex matrix of the attribute ATTRIB_VERTEX and format\n    glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertexVertices);\n    // Set the texture matrix value and format of the attribute ATTRIB_TEXTURE\n    glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, textureVertices);\n    // Enable the ATTRIB_VERTEX attribute data, the default is off\n    glEnableVertexAttribArray(ATTRIB_VERTEX);\n    // Enable the ATTRIB_TEXTURE attribute data, the default is off\n    glEnableVertexAttribArray(ATTRIB_TEXTURE);\n    \n    // Create y, u, v texture objects respectively    \n    impl->mTextureY = new QOpenGLTexture(QOpenGLTexture::Target2D);\n    impl->mTextureU = new QOpenGLTexture(QOpenGLTexture::Target2D);\n    impl->mTextureV = new QOpenGLTexture(QOpenGLTexture::Target2D);\n    impl->mTextureY->create();\n    impl->mTextureU->create();\n    impl->mTextureV->create();\n\n    // Get the texture index value of the return y component\n    impl->id_y = impl->mTextureY->textureId();\n    // Get the texture index value of the returned u component\n    impl->id_u = impl->mTextureU->textureId();\n    // Get the texture index value of the returned v component\n    impl->id_v = impl->mTextureV->textureId();\n\n    glClearColor (0.3, 0.3, 0.3, 0.0); // set the background color\n//    qDebug(\"addr=%x id_y = %d id_u=%d id_v=%d\\n\", this, impl->id_y, impl->id_u, impl->id_v);\n}\n\nvoid OpenGLDisplay::paintGL()\n{\n    std::unique_lock<std::mutex> lock(impl->m_mutex);\n\n    if (!impl->mBufYuv) {\n        return;\n    }\n\n    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);\n\n    // Load y data texture\n    // Activate the texture unit GL_TEXTURE0\n    glActiveTexture(GL_TEXTURE0);\n    // Use the texture generated from y to generate texture\n    glBindTexture(GL_TEXTURE_2D, impl->id_y);\n\n    // Fixes abnormality with 174x100 yuv data\n    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);\n    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);\n    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);\n    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);\n\n    // Use the memory mBufYuv data to create a real y data texture\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, impl->mVideoW, impl->mVideoH, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, impl->mBufYuv);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    // Load u data texture\n    glActiveTexture(GL_TEXTURE1);//Activate texture unit GL_TEXTURE1\n    glBindTexture(GL_TEXTURE_2D, impl->id_u);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, impl->mVideoW/2, impl->mVideoH/2\n                 , 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, static_cast<char*>(impl->mBufYuv) + impl->mVideoW * impl->mVideoH);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    // Load v data texture\n    glActiveTexture(GL_TEXTURE2);//Activate texture unit GL_TEXTURE2\n    glBindTexture(GL_TEXTURE_2D, impl->id_v);\n    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, impl->mVideoW / 2, impl->mVideoH / 2\n                 , 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, static_cast<char*>(impl->mBufYuv) + impl->mVideoW * impl->mVideoH * 5/4);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);\n    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);\n    // Specify y texture to use the new value can only use 0, 1, 2, etc. to represent\n    // the index of the texture unit, this is the place where opengl is not humanized\n    //0 corresponds to the texture unit GL_TEXTURE0 1 corresponds to the\n    // texture unit GL_TEXTURE1 2 corresponds to the texture unit GL_TEXTURE2\n    glUniform1i(impl->textureUniformY, 0);\n    // Specify the u texture to use the new value\n    glUniform1i(impl->textureUniformU, 1);\n    // Specify v texture to use the new value\n    glUniform1i(impl->textureUniformV, 2);\n    // Use the vertex array way to draw graphics\n    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);\n\n    glFlush();\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\nvoid OpenGLDisplay::updateFrame(IFrameDecoder* decoder, unsigned int generation)\n{\n    FrameRenderingData data;\n    if (decoder->getFrameRenderingData(&data))\n    {\n        std::unique_lock<std::mutex> lock(impl->m_mutex);\n\n        impl->m_aspectRatio = float(data.height) / data.width;\n\n        impl->mVideoW = data.width;\n        impl->mVideoH = data.height;\n\n        InitDrawBuffer(data.height * data.width * 3 / 2);\n\n        auto dst = reinterpret_cast<unsigned char*>(impl->mBufYuv);\n        int width = data.width;\n        int height = data.height;\n        for (int i = 0; i < 3; ++i)\n        {\n            auto src = data.image[i];\n            for (int j = 0; j < height; ++j)\n            {\n                memcpy(dst, src, width);\n                dst += width;\n                src += data.pitch[i];\n            }\n            width = data.width / 2;\n            height = data.height / 2;\n        }\n    }\n\n    finishedDisplayingFrame(generation);\n}\n\n\nvoid OpenGLDisplay::showPicture(const QImage& img)\n{\n    if (img.isNull()) {\n        return;\n    }\n\n    if(img.format()!=QImage::Format_RGB32 && img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_RGB888)\n    {\n       Q_ASSERT(false && \"Wrong image format\\n\");\n       return;\n    }\n\n    const auto step = (img.format() == QImage::Format_RGB888)? 3 : 4;\n\n    const int width = img.width() & ~1;\n    const int height = img.height() & ~1;\n\n    std::unique_lock<std::mutex> lock(impl->m_mutex);\n\n    impl->m_aspectRatio = float(height) / width;\n\n    // RGB to YUV420\n    impl->mVideoW = width;\n    impl->mVideoH = height;\n\n    InitDrawBuffer(height * width * 3 / 2);\n\n    int size = width*height;\n    // Y\n    for(unsigned y=0;y<height;y++)\n    {\n       const auto *s = img.scanLine(y);\n       unsigned char *d = reinterpret_cast<unsigned char*>(impl->mBufYuv) + y*width;\n\n       for(unsigned x=0;x<width;x++)\n       {\n          unsigned int r=s[2];\n          unsigned int g=s[1];\n          unsigned int b=s[0];\n\n          unsigned Y = std::min((r*2104 + g*4130 + b*802 + 4096 + 131072) >> 13, 235U);\n          *d = Y;\n\n          d++;\n          s+=step;\n       }\n    }\n\n    // U,V\n    const unsigned int ss = img.bytesPerLine();\n    for(unsigned y=0;y<height;y+=2)\n    {\n       const auto *s = img.scanLine(y);\n       unsigned char *d = reinterpret_cast<unsigned char*>(impl->mBufYuv) + size+y/2*width/2;\n\n       for(unsigned x=0;x<width;x+=2)\n       {\n          // Cr = 128 + 1/256 * ( 112.439 * R'd -  94.154 * G'd -  18.285 * B'd)\n          // Cb = 128 + 1/256 * (- 37.945 * R'd -  74.494 * G'd + 112.439 * B'd)\n\n          // Get the average RGB in a 2x2 block\n          int r=(s[2] + s[step+2] + s[ss+2] + s[ss+step+2] + 2) >> 2;\n          int g=(s[1] + s[step+1] + s[ss+1] + s[ss+step+1] + 2) >> 2;\n          int b=(s[0] + s[step] + s[ss+0] + s[ss+step] + 2) >> 2;\n\n          int Cb = std::clamp((-1214*r - 2384*g + 3598*b + 4096 + 1048576)>>13, 16, 240);\n          int Cr = std::clamp((3598*r - 3013*g - 585*b + 4096 + 1048576)>>13, 16, 240);\n\n          *d = Cb;\n          *(d+size/4) = Cr;\n\n          d++;\n          s+=step * 2;\n       }\n    }\n\n    lock.unlock();\n    emit update();\n}\n\nvoid OpenGLDisplay::showPicture(const QPixmap& picture)\n{\n    showPicture(picture.toImage());\n}\n\nvoid OpenGLDisplay::drawFrame(IFrameDecoder* decoder, unsigned int generation)\n{\n    if (!(impl->m_pendingUpdate.exchange(true)))\n    {\n        QMetaObject::invokeMethod(this, [this]\n            {\n                impl->m_pendingUpdate = false;\n                setUpdatesEnabled(true);\n                update();\n            });\n    }\n    //finishedDisplayingFrame(generation);\n}\n\nvoid OpenGLDisplay::decoderClosing()\n{\n}\n\nfloat OpenGLDisplay::aspectRatio() const { return impl->m_aspectRatio; }\n"
  },
  {
    "path": "QtPlayer/opengldisplay.h",
    "content": "#ifndef OPENGLDISPLAY_H\n#define OPENGLDISPLAY_H\n\n// https://github.com/MasterAler/SampleYUVRenderer\n\n#include <QOpenGLWidget>\n#include <QOpenGLFunctions>\n#include <QScopedPointer>\n#include <QException>\n\n#include \"videodisplay.h\"\n\nclass OpenGLDisplay : public QOpenGLWidget, public QOpenGLFunctions, public VideoDisplay\n{\n    Q_OBJECT\npublic:\n    explicit OpenGLDisplay(QWidget* parent = nullptr);\n    ~OpenGLDisplay() override;\n\n    void InitDrawBuffer(unsigned bsize);\n\n    void showPicture(const QImage& img) override;\n    void showPicture(const QPixmap& picture) override;\n\n    // decoder->finishedDisplayingFrame() must be called\n    void updateFrame(IFrameDecoder* decoder, unsigned int generation) override;\n    void drawFrame(IFrameDecoder* decoder, unsigned int generation) override;\n    void decoderClosing() override;\n\n    float aspectRatio() const;\n\nprotected:\n    void initializeGL() override;\n    void paintGL() override;\n\nprivate:\n    struct OpenGLDisplayImpl;\n    QScopedPointer<OpenGLDisplayImpl> impl;\n};\n\n/***********************************************************************/\n\nclass OpenGlException: public QException\n{\npublic:\n     void raise() const override { throw *this; }\n     OpenGlException *clone() const override { return new OpenGlException(*this); }\n};\n\n#endif // OPENGLDISPLAY_H\n"
  },
  {
    "path": "QtPlayer/portaudioplayer.cpp",
    "content": "#include \"portaudioplayer.h\"\n\n#include <portaudio.h>\n#include <QThread>\n\nPortAudioPlayer::PortAudioPlayer()\n{\n    auto err = Pa_Initialize();\n}\n\nPortAudioPlayer::~PortAudioPlayer()\n{\n    auto err = Pa_Terminate();\n}\n\nvoid PortAudioPlayer::InitializeThread()\n{\n    QThread::currentThread()->setPriority(QThread::TimeCriticalPriority);\n}\n\nbool PortAudioPlayer::Open(int bytesPerSample, int channels, int* samplesPerSec)\n{\n    PaStreamParameters params{};\n    params.device = Pa_GetDefaultOutputDevice();\n    params.suggestedLatency = Pa_GetDeviceInfo(params.device)->defaultLowOutputLatency;\n    params.channelCount = channels;\n\n    switch (bytesPerSample)\n    {\n    case 1:\n        params.sampleFormat = paInt8;\n        break;\n    case 2:\n        params.sampleFormat = paInt16;\n        break;\n    case 4:\n        params.sampleFormat = paInt32;\n        break;\n    }\n\n    auto err{ Pa_OpenStream(&m_stream, nullptr, &params, *samplesPerSec, paFramesPerBufferUnspecified,\n        paNoFlag, nullptr, nullptr) };\n\n    if (err != paNoError) {\n        return false;\n    }\n\n    err = Pa_StartStream(m_stream);\n\n    m_FrameSize = bytesPerSample * channels;\n\n    *samplesPerSec = m_samplesPerSec = Pa_GetStreamInfo(m_stream)->sampleRate;\n\n    return true;\n}\n\nvoid PortAudioPlayer::Close()\n{\n    auto err = Pa_CloseStream(m_stream);\n    m_stream = nullptr;\n}\n\nbool PortAudioPlayer::WriteAudio(uint8_t* write_data, int64_t write_size)\n{\n    if (!m_stream) {\n        return false;\n    }\n\n    auto* realData = (int16_t*)write_data;\n    for (unsigned int i = 0; i < write_size / 2; ++i) {\n        realData[i] *= m_volume;\n    }\n\n    const auto framesToWrite = write_size / m_FrameSize;\n    auto err = Pa_WriteStream(m_stream, write_data, framesToWrite);\n    if (err == paStreamIsStopped && Pa_StartStream(m_stream) == paNoError)\n    {\n        err = Pa_WriteStream(m_stream, write_data, framesToWrite);\n    }\n\n    // count audio pts\n    const double frame_clock = (double)framesToWrite / m_samplesPerSec;\n    m_callback->AppendFrameClock(frame_clock);\n\n    return err == paNoError;\n}\n\nvoid PortAudioPlayer::WaveOutReset()\n{\n    Pa_AbortStream(m_stream);\n}\n\nvoid PortAudioPlayer::WaveOutPause()\n{\n    Pa_StopStream(m_stream);\n}\n\nvoid PortAudioPlayer::WaveOutRestart()\n{\n    Pa_StartStream(m_stream);\n}\n"
  },
  {
    "path": "QtPlayer/portaudioplayer.h",
    "content": "#pragma once\n\n#include \"../video/audioplayer.h\"\n\n\nclass PortAudioPlayer :\n    public IAudioPlayer\n{\npublic:\n    PortAudioPlayer();\n    ~PortAudioPlayer() override;\n\n    PortAudioPlayer(const PortAudioPlayer&) = delete;\n    PortAudioPlayer& operator=(const PortAudioPlayer&) = delete;\n\n    void SetCallback(IAudioPlayerCallback* callback) override\n    {\n        m_callback = callback;\n    }\n\n    void InitializeThread() override;\n    void DeinitializeThread() override {}\n\n    void WaveOutReset() override;\n\n    void Close() override;\n    bool Open(int bytesPerSample, int channels, int* samplesPerSec) override;\n\n    void SetVolume(double volume) override { m_volume = volume; }\n    double GetVolume() const override { return m_volume; }\n\n    void WaveOutPause() override;\n    void WaveOutRestart() override;\n\n    bool WriteAudio(uint8_t* write_data, int64_t write_size) override;\n\nprivate:\n    IAudioPlayerCallback* m_callback{};\n    void* m_stream{};\n\n    int m_FrameSize{};\n    double m_samplesPerSec{};\n    double m_volume = 1.;\n};\n"
  },
  {
    "path": "QtPlayer/resources/qt.conf",
    "content": "[Paths]\nPlugins = ."
  },
  {
    "path": "QtPlayer/resources/resources.qrc",
    "content": "<RCC>\n    <qresource prefix=\"/\">\n        <file>style.css</file>\n        <file>images/help41.png</file>\n        <file alias=\"button_disable.png\">images/style/button_disable.png</file>\n        <file alias=\"button_down.png\">images/style/button_down.png</file>\n        <file alias=\"button_hover.png\">images/style/button_hover.png</file>\n        <file alias=\"button_normal.png\">images/style/button_normal.png</file>\n        <file alias=\"header_arrow_down\">images/style/header_arrow_down.png</file>\n        <file>images/style/down_arrow.png</file>\n        <file>images/style/lineedit.png</file>\n        <file>images/style/down_arrow_grey.png</file>\n        <file>images/play_transparent.png</file>\n        <file>images/video___btn_play___default___(94x94).png</file>\n        <file>images/video___btn_play___hover___(94x94).png</file>\n        <file>images/video___btn_play___clicked___(94x94).png</file>\n        <file alias=\"box-shadow\">images/style/box-shadow.png</file>\n        <file alias=\"busy\">images/style/busy.png</file>\n        <file alias=\"button-blank\">images/style/button-blank.png</file>\n        <file alias=\"floatpanel\">images/style/floatpanel.png</file>\n        <file>images/spinner.gif</file>\n        <file>images/triangle_down.png</file>\n        <file>images/triangle_right.png</file>\n        <file>images/style/progress_dropdown.png</file>\n        <file alias=\"circle-shadow\">images/style/circle-shadow.png</file>\n        <file alias=\"tooltip-background.png\">images/style/tooltip-background.png</file>\n        <file>images/video_seek_cursor.png</file>\n    </qresource>\n    <qresource prefix=\"/style\">\n        <file alias=\"header_line.png\">images/style/header_line.png</file>\n        <file alias=\"scroll-button-down.png\">images/style/scroll-button-down.png</file>\n        <file alias=\"scroll-button-down-hover.png\">images/style/scroll-button-down-hover.png</file>\n        <file alias=\"scroll-button-up.png\">images/style/scroll-button-up.png</file>\n        <file alias=\"scroll-button-up-hover.png\">images/style/scroll-button-up-hover.png</file>\n        <file alias=\"scroll-vhandle.png\">images/style/scroll-vhandle.png</file>\n        <file alias=\"scroll-vhandle-hover.png\">images/style/scroll-vhandle-hover.png</file>\n        <file alias=\"scroll-button-left.png\">images/style/scroll-button-left.png</file>\n        <file alias=\"scroll-button-left-hover.png\">images/style/scroll-button-left-hover.png</file>\n        <file alias=\"scroll-button-right.png\">images/style/scroll-button-right.png</file>\n        <file alias=\"scroll-button-right-hover.png\">images/style/scroll-button-right-hover.png</file>\n        <file alias=\"scroll-hhandle.png\">images/style/scroll-hhandle.png</file>\n        <file alias=\"scroll-hhandle-hover.png\">images/style/scroll-hhandle-hover.png</file>\n    </qresource>\n    <qresource prefix=\"/control\">\n        <file alias=\"background\">images/control/player_bg___(230x41).png</file>\n        <file alias=\"backgroundfs\">images/control/player_bg_fs___(230x41).png</file>\n        <file alias=\"play_default\">images/control/player___btn_play___default___(40x31).png</file>\n        <file alias=\"play_clicked\">images/control/player___btn_play___clicked___(40x31).png</file>\n        <file alias=\"play_hover\">images/control/player___btn_play___hover___(40x31).png</file>\n        <file alias=\"stop_default\">images/control/player___btn_stop___default___(31x31).png</file>\n        <file alias=\"stop_clicked\">images/control/player___btn_stop___clicked___(31x31).png</file>\n        <file alias=\"stop_hover\">images/control/player___btn_stop___hover___(31x31).png</file>\n        <file alias=\"globe_default\">images/control/player___btn_globe___default___(31x31).png</file>\n        <file alias=\"globe_clicked\">images/control/player___btn_globe___click___(31x31).png</file>\n        <file alias=\"globe_hover\">images/control/player___btn_globe___hover___(31x31).png</file>\n        <file alias=\"sound_on_default\">images/control/player___btn_sound_on___default___(31x31).png</file>\n        <file alias=\"sound_on_clicked\">images/control/player___btn_sound_on___clicked___(31x31).png</file>\n        <file alias=\"sound_on_hover\">images/control/player___btn_sound_on___hover___(31x31).png</file>\n        <file alias=\"sound_off_default\">images/control/player___btn_sound_off___default___(31x31).png</file>\n        <file alias=\"sound_off_clicked\">images/control/player___btn_sound_off___clicked___(31x31).png</file>\n        <file alias=\"sound_off_hover\">images/control/player___btn_sound_off___hover___(31x31).png</file>\n        <file alias=\"pause_default\">images/control/player___btn_pause___default___(40x31).png</file>\n        <file alias=\"pause_clicked\">images/control/player___btn_pause___clicked___(40x31).png</file>\n        <file alias=\"pause_hover\">images/control/player___btn_pause___hover___(40x31).png</file>\n        <file alias=\"icodelete\">images/control/icodelete.png</file>\n        <file alias=\"icoplay\">images/control/icoplay.png</file>\n    </qresource>\n</RCC>\n"
  },
  {
    "path": "QtPlayer/resources/style.css",
    "content": "/* ********** Global settings ********** */\nQWidget\n{\n\tfont-family: \"Segoe UI\";\n\tfont-size: 12px;\n}\n\nQDialog\n{\n\tborder: 0px;\n}\n\nQMainWindow::separator {\n\tbackground: rgb(128, 133, 137);\n\twidth: 3;\n\theight: 3;\n}\n\nQPushButton,\nQDialogButtonBox QPushButton,\nButtonLabel\n{\n\t/*See in PS for cut lines*/\n\tborder-image: url(:/button_normal) 4 5 6 5;\n\tborder-top: 4px transparent;\n\tborder-right: 5px transparent;\n\tborder-bottom: 4px transparent;\n\tborder-left: 5px transparent;\n\tpadding-left:-1px;\n\tmin-width: 6em;\n\theight: 16 px;\n}\nSearchResultForm QPushButton\n{\n\tmin-width: 62px;\n}\n\nQPushButton:hover,\nQDialogButtonBox QPushButton:hover, \nButtonLabel:hove\n{\n\tborder-image: url(:/button_hover) 4 5 6 5;\n}\n\nQPushButton:pressed,\nQDialogButtonBox QPushButton:pressed,\nButtonLabel:pressed\n{\n\tborder-image: url(:/button_down) 4 5 6 5;\n\tpadding-top:2px;\n}\n\nQPushButton:disabled,\nQDialogButtonBox QPushButton:disabled,\nButtonLabel:disabled\n{\n\tborder-image: url(:/button_disable) 4 5 6 5;\n\tcolor: #8f8f8f;\n}\n\n#mainToolBar\n{\n\tborder-bottom: 1px solid #5d6c7a;\n\tbackground-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 #d4d4d5, stop:1 #ffffff);\n}\n\nMainToolBar QToolButton {\n\tborder: 0px;\n}\n\n#SocialNetworksFrame QToolButton {\n\tborder: 0px;\n}\n\nMainToolBar QLabel {\n   color: rgb(95, 100, 104);\n}\n\nMainToolBar  #btnDownloads[active=\"false\"] {\n\timage: url(:/images/downloads41.png);\n}\n\nMainToolBar  #btnDownloads[active=\"true\"]{\n\timage: url(:/images/downloads41h.png);\n}\n\nMainToolBar  #btnSearch[active=\"false\"] {\n\timage: url(:/images/search41.png);\n}\n\nMainToolBar   #btnSearch[active=\"true\"]{\n\timage: url(:/images/search41h.png);\n}\n\nMainToolBar  #btnLibrary[active=\"false\"] {\n\timage: url(:/images/library41.png);\n}\n\nMainToolBar  #btnLibrary[active=\"true\"]{\n\timage: url(:/images/library41h.png);\n}\n/*\nSearchResultForm #searchFrame {\n\tbackground-color: rgb(148, 153, 157);\n} */\n\n#topFrame{\n\tbackground-color: rgb(148, 153, 157);\n}\n\nQTreeView, #declarativeView, #dockFrame, QTableView {\n\tborder-top: 1px solid #5d6c7a;\n}\n\n#dockFrame{\n\tbackground-color: lightgrey;\n}\n\nSearchResultForm #leSearch,\nDownloadsForm #leSearch,\nLibraryForm #cbSearch {\n\t/*background-color: rgb(125, 130, 134);\n\tselection-background-color: #b3b7b9;*/\n\tbackground: #e4e7e9;\n\tcolor: black;\n\t\t\n\tborder: 0px;\n\theight: 22px;\n\tfont-size: 14px;\n}\n\nDownloadsControl #ctrlFrame {\n\tborder-width: 1px;\n\tborder-style: inset;\n\tborder-color: #535353;\n\tborder-radius: 5px;\n\tbackground-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #dedede, stop:1 #b1b2b3);\n}\n\n/*\nPlayerHeader QFrame{\n\tbackground-color: rgb(148, 153, 157);\n\tcolor: white;\n\tfont-size: 14px;\n}\n*/\n\nQComboBox#cbSites QAbstractItemView::item {\n\tmargin-top: 5px;\n\tcolor: rgb(148, 153, 157);\t\n}\nSearchResultForm QHeaderView::section,DownloadsForm QHeaderView::section {\n\tbackground-color: qlineargradient(x1:0, y1:0, x2:0, y2:1,\n\t\t\t\t\t\t\t\t\t   stop:0 rgb(237, 243, 248), \n\t\t\t\t\t\t\t\t\t   stop:1 rgb(211, 225, 238));\n\n\tpadding-left: 4px;\n\tborder: 0px;\n\theight: 30px;\n\tborder-top: 1px solid rgb(165, 184, 195);\n\tborder-bottom: 1px solid rgb(165, 184, 195);\n\tfont-size: 14px;\n}\n/*\nQComboBox {\n\tborder-image: url(:/images/style/lineedit.png) 3;\n\tborder-width: 3;\n}\n\nQComboBox::drop-down\n{\n\tborder-style: none;\n}\n\nQComboBox::down-arrow\n{\n\timage: url(:/images/style/down_arrow_grey.png);\n}\n*/\n\nQComboBox#cbSites {\n\tborder: 1px solid gray;\n\tpadding: 1px 22px 1px 3px;\n\tmin-width: 9em;\n\tbackground: #e4e7e9;\n\theight: 20px;\n}\nQComboBox#cbSites::drop-down\n{\n\tborder-style: none;\n}\n\n QComboBox#cbSites::drop-down {\n\tsubcontrol-origin: padding;\n\tsubcontrol-position: top right;\n\twidth: 22px;\n\n\tborder-left-width: 1px;\n\tborder-left-color: #c9ccd2;\n\tborder-left-style: solid; /* just a single line */\n}\n\nQComboBox#cbSites::down-arrow {\n\timage: url(:/images/style/down_arrow_grey.png);\n}\n\nAboutDialog {\n\tbackground-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(220, 220, 220, 255), stop:0.460227 rgba(229, 229, 229, 255), stop:1 rgba(239, 239, 239, 255));\n}\n\nAboutDialog #aboutHeader {\n\tbackground-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 rgba(184, 188, 192, 255), stop:0.460227 rgba(190, 195, 198, 255), stop:1 rgba(213, 219, 224, 255));\n}\n\nAboutDialog #lbAppName {\n\tfont-size: 24px;\n\tcolor: white;\n}\n\nAboutDialog #wLine\n{\n\tbackground:url(:/style/header_line.png);\n}\nVideoControl #playerControlFrame {\n\tbackground-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 #e5e8ea, stop:1 #ffffff);\n\tborder-color: #75787a;\n\tborder-width: 1px;\n\tborder-style: outset;\n\tborder-radius: 5px;\n}\n\nVideoControl QProgressBar {\n\tborder-color: #777777;\n\tborder-width: 1px;\n\tborder-style: outset;\n\tborder-radius: 2px;\n}\nVideoControl QProgressBar::chunk {   \n\tbackground-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 #278ece, stop:1 #5dc6f8);\n\tborder-width: 1px;\n\tborder-style: outset;\n\tborder-radius: 5px;\n\tmargin: 1px;\n }\nVideoControl QToolButton {\nborder: 0px;\n}\n\nDownloadsControl #frame {\n\tbackground-color: qlineargradient(spread:pad, x1:1, y1:1, x2:1, y2:0, stop:0 #e5e8ea, stop:1 #ffffff);\n\tborder-color: #75787a;\n\tborder-width: 1px;\n\tborder-style: outset;\n\tborder-radius: 5px;\n}\n\nDownloadsControl QToolButton {\nborder: 0px;\n}\n\nDownloadsControl QFrame  #line{\n\tcolor:green;\n\tmargin-top: 2px;\n\tmargin-bottom: 2px;\n}\n \nQScrollBar::add-line:vertical { \nbackground-image: url(:/style/scroll-button-down.png);\n} \nQScrollBar::sub-line:vertical { \nbackground-image: url(:/style/scroll-button-up.png);\n} \n\nQScrollBar::add-page:vertical,\nQScrollBar::sub-page:vertical,\nQScrollBar::add-page:horizontal,\nQScrollBar::sub-page:horizontal\n{\n\tbackground: none;\n}\n\nQScrollBar:vertical\n{\n\tbackground: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,\n\t\tstop: 0 #e9e8e9, stop: 0.5 #d3d3d3, stop: 1.0 #e9e8e9);\n\twidth: 14px;\n\tpadding: 14px 0px 14px 0px;\n}\n\nQScrollBar::handle:vertical\n{\n\tbackground: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,\n\t\tstop: 0 #fafafa, stop: 0.5 #e9e9e9, stop: 1.0 #c7c7c7);\n\tborder-radius: 2px;\n\tborder: 1px solid #787878;\n\tmin-height: 20px;\n }\n\nQScrollBar:horizontal\n{\n\tbackground: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,\n\t\tstop: 0 #e9e8e9, stop: 0.5 #d3d3d3, stop: 1.0 #e9e8e9);\n\theight: 14px;\n\tpadding:  0px 14px 0px 14px;\n}\n\nQScrollBar::handle:horizontal\n{\n\tbackground: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,\n\t\tstop: 0 #fafafa, stop: 0.5 #e9e9e9, stop: 1.0 #c7c7c7);\n\tborder-radius: 2px;\n\tborder: 1px solid #787878;\n\tmin-width: 20px;\n}\n\n#DescriptionFrame #textEdit\n{\n\tbackground-color: rgb(211, 211, 211);\n\tborder: 0px;\n\tpadding: 3px 2px 3px 4px;\n\tborder-top: 1px solid rgb(180, 180, 180);\n}\n\n#descriptionSiteLabel {\n\tcolor: rgb(155, 155, 155);\n\tfont: 75 11pt \"MS Shell Dlg 2\";\n\tmargin-left: 7px;\n\tmargin-top: 3px;\n\tmargin-bottom: 3px;\n}\n\nSocialNetworksWidget #SocialNetworksFrame {\n\tbackground-image: url(:/sites/social_bg);\n}\n\n\n"
  },
  {
    "path": "QtPlayer/resources/win7.manifest",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?> \n  <assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\"> \n   <trustInfo xmlns=\"urn:schemas-microsoft-com:asm.v3\">\n    <security>\n      <requestedPrivileges>\n        <requestedExecutionLevel level=\"asInvoker\" uiAccess=\"false\"></requestedExecutionLevel>\n      </requestedPrivileges>\n    </security>\n  </trustInfo>\n    <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\"> \n    <application> \n        <supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\"/> \n        <supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\"/> \n        <supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\"/>\n    </application> \n  </compatibility>\n  </assembly>\n"
  },
  {
    "path": "QtPlayer/resources/winres.rc.in",
    "content": "#include \"verrsrc.h\"\n\nIDI_ICON1               ICON                    \"@ICON_FILE@\"\n\n#define VER_FILEVERSION             @MAJOR_VER@,@MINOR_VER1@,@MINOR_VER2@,@MINOR_VER3@\n#define VER_FILEVERSION_STR         \"@MAJOR_VER@.@MINOR_VER1@.@MINOR_VER2@.@MINOR_VER3@\\0\"\n\n#define VER_PRODUCTVERSION          @MAJOR_VER@,@MINOR_VER1@,@MINOR_VER2@,@MINOR_VER3@\n#define VER_PRODUCTVERSION_STR     \t\"@MAJOR_VER@.@MINOR_VER1@.@MINOR_VER2@.@MINOR_VER3@\\0\"\n\n\n1 VERSIONINFO\n FILEVERSION VER_FILEVERSION\n PRODUCTVERSION VER_PRODUCTVERSION\n FILEFLAGSMASK 0x3fL\n#ifdef _DEBUG\n FILEFLAGS 0x1L\n#else\n FILEFLAGS 0x0L\n#endif\n FILEOS VOS_NT_WINDOWS32\n FILETYPE VFT_APP\n FILESUBTYPE 0x0L\n BEGIN\n\tBLOCK \"StringFileInfo\"\n\tBEGIN\n\t\tBLOCK \"040904e4\"\n\t\tBEGIN\n\t\t\tVALUE \"CompanyName\", \"@COMPANYNAME@\\0\"\n\t\t\tVALUE \"FileDescription\", \"@PRODUCTNAME@\\0\"\n\t\t\tVALUE \"FileVersion\", VER_FILEVERSION_STR\n\t\t\tVALUE \"LegalCopyright\", \"Copyright (C) 2013 @COMPANYNAME@ All Rights Reserved.\\0\"\n\t\t\tVALUE \"ProductName\", \"@PRODUCTNAME@\\0\"\n\t\t\tVALUE \"ProductVersion\", VER_PRODUCTVERSION_STR\n\t\t\tVALUE \"OriginalFilename\", \"@SHORTPRODUCTNAME@.exe\\0\"\n\t\t\tVALUE \"InternalName\", \"@SHORTPRODUCTNAME@\\0\"\n\t\tEND\n\tEND\n\tBLOCK \"VarFileInfo\"\n\tBEGIN\n\t\t/* The following line should only be modified for localized versions.     */\n\t\t/* It consists of any number of WORD,WORD pairs, with each pair           */\n\t\t/* describing a language,codepage combination supported by the file.      */\n\t\t/*                                                                        */\n\t\t/* For example, a file might have values \"0x409,1252\" indicating that it  */\n\t\t/* supports English language (0x409) in the Windows ANSI codepage (1252). */\n\n\t\tVALUE \"Translation\", 0x409, 1252\n\tEND\n END\n"
  },
  {
    "path": "QtPlayer/videocontrol.cpp",
    "content": "#include \"videocontrol.h\"\n#include \"ui_videocontrol.h\"\n\n#include \"videoplayerwidget.h\"\n#include \"videowidget.h\"\n\n#include <QPainter>\n#include <QMouseEvent>\n\n#include <QtWidgets/qdrawutil.h>\n\n#include <algorithm>\n\nVideoControl::VideoControl(VideoPlayerWidget* parent)\n\t: QWidget(parent), ui(new Ui::VideoControl) \n{\n\tui->setupUi(this);\n\n\tui->progressBar->installEventFilter(this);\n\n\t// Link it with VideoPlayerWidget\n\tparent->setControl(this);\n\tvideoPlayer = parent;\n\n\t// Default value from the decoder\n\tint volume = videoPlayer->getDecoder()->volume() * ui->progressBar->maximum();\n\tm_isVolumeOn = (volume == 0);\n\n\tsetVolume(volume, true);\n\n    connect(videoPlayer->getDecoder(), &FFmpegDecoderWrapper::volumeChanged, this, &VideoControl::onProgramVolumeChange);\n\tui->btnPause->hide();\n\n\tm_height = geometry().height();\n\n\tbackground.load(\":/control/background\");\n\tbackgroundfs.load(\":/control/backgroundfs\");\n}\n\nVideoControl::~VideoControl()\n{\n\tdelete ui;\n}\n\nbool VideoControl::eventFilter(QObject* obj, QEvent* event)\n{\n\tif (obj == ui->progressBar)\n\t{\n\t\tQEvent::Type eventType = event->type();\n\t\tswitch (eventType)\n\t\t{\n\t\tcase QEvent::MouseMove:\n\t\t{\n\t\t\tauto* mEvent = static_cast<QMouseEvent*>(event);\n\t\t\tif (mEvent->buttons() & Qt::LeftButton)\n\t\t\t{\n\t\t\t\tfloat percent = (mEvent->x() * 1.0) / ui->progressBar->width();\n\t\t\t\tpercent *= 100;\n\t\t\t\tsetVolume(qBound(0, static_cast<int>(percent), 100));\n\t\t\t}\n\t\t}\n\t\tbreak;\n\n\t\tcase QEvent::MouseButtonRelease:\n\t\t{\n\t\t\tauto* mEvent = static_cast<QMouseEvent*>(event);\n\t\t\tif (mEvent->button() == Qt::LeftButton)\n\t\t\t{\n\t\t\t\tfloat percent = (mEvent->x() * 1.0) / ui->progressBar->width();\n\t\t\t\tpercent *= 100;\n\t\t\t\tsetVolume(qBound(0, static_cast<int>(percent), 100));\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t\tdefault:;\n\t\t}\n\n\t}\n\treturn QWidget::eventFilter(obj, event);\n}\n\nvoid VideoControl::paintEvent(QPaintEvent* event)\n{\n\tQ_UNUSED(event);\n\tQPainter painter(this);\n\n    qDrawBorderPixmap(&painter, rect(), QMargins(0, 0, 0, 0),\n                      parent() == nullptr ? backgroundfs : background);\n}\n\nvoid VideoControl::resizeEvent(QResizeEvent* event)\n{\n\tQ_UNUSED(event);\n\t// separators on background image (got from the image)\n\tconst int leftSeparator = 94;\n\tconst int rightSeparator = 137;\n\n\t// margin by X between the controls\n\tconst int margin = (leftSeparator - ui->btnPlay->width() - ui->btnStop->width()) / 3;\n\n\t// position by Y for the buttons\n\tconst int posY = (background.height() - ui->btnPlay->height()) / 2;\n\n\tui->btnPlay->move(2 * margin, posY);\n\tui->btnPause->move(2 * margin, posY);\n\n\tui->btnStop->move(3 * margin + ui->btnPlay->width(), posY);\n\n\tui->btnBrowser->move(((rightSeparator - leftSeparator) - ui->btnBrowser->width()) / 2 + leftSeparator, posY);\n\n\tui->btnVolume->move(rightSeparator + margin, posY);\n\n\tui->progressBar->move(ui->btnVolume->pos().x() + ui->btnVolume->width(), (height() - ui->progressBar->height()) / 2 + 1); // +1 for just more nice looking\n\tui->progressBar->setFixedSize(width() - ui->progressBar->pos().x() - 3 * margin, ui->progressBar->height());\n}\n\nvoid VideoControl::wheelEvent(QWheelEvent* event)\n{\n    if (event->orientation() != Qt::Horizontal)\n    {\n        if (auto decoder = videoPlayer->getDecoder())\n        {\n            const int numDegrees = event->delta() / 8;\n            const int numSteps = numDegrees / 15;\n            const double newVolume = std::clamp(decoder->volume() + ((double)numSteps / 20), 0., 1.);\n            decoder->setVolume(newVolume);\n        }\n    }\n    event->accept();\n}\n\nint VideoControl::getWidth() const\n{\n\treturn background.width();\n}\n\nvoid VideoControl::on_btnVolume_clicked()\n{\n\tif (ui->progressBar->value() > 0)\n\t{\n\t\tsetVolume(0);\n\t}\n\telse\n\t{\n\t\tint volume = m_prevVolumeValue;\n\t\tif (volume <= 0)\n\t\t{\n\t\t\tvolume = 50;\n\t\t}\n\t\tsetVolume(volume);\n\t}\n}\n\nvoid VideoControl::setVolume(int volume, bool onlyWidget)\n{\n\tui->progressBar->setValue(volume);\n\n\tswitchVolumeButton(volume != 0);\n\n    int prevVolumeValue = videoPlayer->getDecoder()->volume() * ui->progressBar->maximum();\n    if ((videoPlayer != nullptr) && !onlyWidget)\n    {\n        videoPlayer->getDecoder()->setVolume(\n                    ui->progressBar->maximum() != 0? (double(volume) / ui->progressBar->maximum()) : 0.);\n    }\n    m_prevVolumeValue = prevVolumeValue;\n}\n\nvoid VideoControl::switchVolumeButton(bool volumeOn)\n{\n\tQIcon progressBarIcon;\n\tif (m_isVolumeOn && !volumeOn)\n\t{\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_off_default\"), QSize(), QIcon::Normal, QIcon::Off);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_off_clicked\"), QSize(), QIcon::Normal, QIcon::On);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_off_default\"), QSize(), QIcon::Disabled, QIcon::Off);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_off_default\"), QSize(), QIcon::Disabled, QIcon::On);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_off_hover\"), QSize(), QIcon::Active, QIcon::Off);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_off_hover\"), QSize(), QIcon::Active, QIcon::On);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_off_default\"), QSize(), QIcon::Selected, QIcon::Off);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_off_default\"), QSize(), QIcon::Selected, QIcon::On);\n\t\tui->btnVolume->setIcon(progressBarIcon);\n\t\tm_isVolumeOn = volumeOn;\n\t}\n\telse if (!m_isVolumeOn && volumeOn)\n\t{\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_on_default\"), QSize(), QIcon::Normal, QIcon::Off);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_on_clicked\"), QSize(), QIcon::Normal, QIcon::On);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_on_default\"), QSize(), QIcon::Disabled, QIcon::Off);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_on_default\"), QSize(), QIcon::Disabled, QIcon::On);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_on_hover\"), QSize(), QIcon::Active, QIcon::Off);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_on_hover\"), QSize(), QIcon::Active, QIcon::On);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_on_default\"), QSize(), QIcon::Selected, QIcon::Off);\n\t\tprogressBarIcon.addFile(QString::fromUtf8(\":/control/sound_on_default\"), QSize(), QIcon::Selected, QIcon::On);\n\t\tui->btnVolume->setIcon(progressBarIcon);\n\t\tm_isVolumeOn = volumeOn;\n\t}\n}\n\nvoid VideoControl::on_btnPlay_clicked()\n{\n\tvideoPlayer->playPauseButtonAction();\n}\n\nvoid VideoControl::on_btnPause_clicked()\n{\n\tvideoPlayer->playPauseButtonAction();\n}\n\nvoid VideoControl::on_btnStop_clicked()\n{\n\tshowPlaybutton(true);\n\tQ_ASSERT(videoPlayer);\n\tif (videoPlayer->state() != VideoPlayerWidget::InitialState)\n\t{\n\t\tvideoPlayer->stopVideo(true);\n\t}\n}\n\nvoid VideoControl::on_btnBrowser_clicked()\n{\n\temit browse();\n}\n\nvoid VideoControl::onProgramVolumeChange(double volume)\n{\n\tsetVolume(volume * ui->progressBar->maximum(), true);\n}\n\nvoid VideoControl::showPlaybutton(bool show /* = true */)\n{\n\tui->btnPlay->setVisible(show);\n\tui->btnPause->setVisible(!show);\n}\n"
  },
  {
    "path": "QtPlayer/videocontrol.h",
    "content": "#pragma once\n\n#include <QWidget>\n\nclass VideoPlayerWidget;\n\nnamespace Ui\n{\nclass VideoControl;\n}\n\nclass VideoControl : public QWidget\n{\n\tQ_OBJECT\n\npublic:\n\texplicit VideoControl(VideoPlayerWidget* parent = nullptr);\n\t~VideoControl() override;\n\tvoid setVolume(int volume, bool onlyWidget = false);\n\tvoid showPlaybutton(bool show = true);\n\n\tint getHeight() const { return m_height; };\n\tint getWidth() const;\n\nsignals:\n\tvoid download();\n\tvoid browse();\n\nprotected:\n\tbool eventFilter(QObject* obj, QEvent* event) override;\n\tvoid paintEvent(QPaintEvent* event) override;\n\tvoid resizeEvent(QResizeEvent* event)override;\n    void wheelEvent(QWheelEvent* event) override;\n\npublic slots:\n\tvoid on_btnPlay_clicked();\n\tvoid on_btnPause_clicked();\n\nprivate slots:\n\tvoid onProgramVolumeChange(double volume);\n\tvoid on_btnVolume_clicked();\n\tvoid on_btnStop_clicked();\n\tvoid on_btnBrowser_clicked();\n\nprivate:\n\tUi::VideoControl* ui;\n\tVideoPlayerWidget* videoPlayer;\n\tint m_height;\n\tQPixmap background;\n\tQPixmap backgroundfs;\n\tbool m_isVolumeOn{false};\n\tint m_prevVolumeValue{0};\n\n\tvoid switchVolumeButton(bool volumeOn);\n};\n"
  },
  {
    "path": "QtPlayer/videocontrol.ui",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ui version=\"4.0\">\n <class>VideoControl</class>\n <widget class=\"QWidget\" name=\"VideoControl\">\n  <property name=\"geometry\">\n   <rect>\n    <x>0</x>\n    <y>0</y>\n    <width>230</width>\n    <height>41</height>\n   </rect>\n  </property>\n  <property name=\"sizePolicy\">\n   <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n    <horstretch>0</horstretch>\n    <verstretch>0</verstretch>\n   </sizepolicy>\n  </property>\n  <property name=\"windowTitle\">\n    <string notr=\"true\">Form</string>\n  </property>\n  <property name=\"styleSheet\">\n   <string notr=\"true\"/>\n  </property>\n  <widget class=\"MouseHoverButton\" name=\"btnPause\">\n   <property name=\"geometry\">\n    <rect>\n     <x>31</x>\n     <y>8</y>\n     <width>40</width>\n     <height>31</height>\n    </rect>\n   </property>\n   <property name=\"toolTip\">\n    <string>Pause</string>\n   </property>\n   <property name=\"text\">\n    <string/>\n   </property>\n   <property name=\"icon\">\n    <iconset resource=\"resources/resources.qrc\">\n     <normaloff>:/control/pause_default</normaloff>\n     <normalon>:/control/pause_clicked</normalon>\n     <disabledoff>:/control/pause_default</disabledoff>\n     <disabledon>:/control/pause_default</disabledon>\n     <activeoff>:/control/pause_hover</activeoff>\n     <activeon>:/control/pause_hover</activeon>\n     <selectedoff>:/control/pause_default</selectedoff>\n     <selectedon>:/control/pause_default</selectedon>:/control/pause_default</iconset>\n   </property>\n   <property name=\"iconSize\">\n    <size>\n     <width>40</width>\n     <height>31</height>\n    </size>\n   </property>\n   <property name=\"autoRaise\">\n    <bool>true</bool>\n   </property>\n  </widget>\n  <widget class=\"MouseHoverButton\" name=\"btnStop\">\n   <property name=\"geometry\">\n    <rect>\n     <x>62</x>\n     <y>8</y>\n     <width>31</width>\n     <height>31</height>\n    </rect>\n   </property>\n   <property name=\"toolTip\">\n    <string>Stop</string>\n   </property>\n   <property name=\"text\">\n    <string/>\n   </property>\n   <property name=\"icon\">\n    <iconset resource=\"resources/resources.qrc\">\n     <normaloff>:/control/stop_default</normaloff>\n     <normalon>:/control/stop_clicked</normalon>\n     <disabledoff>:/control/stop_default</disabledoff>\n     <disabledon>:/control/stop_default</disabledon>\n     <activeoff>:/control/stop_hover</activeoff>\n     <activeon>:/control/stop_hover</activeon>\n     <selectedoff>:/control/stop_default</selectedoff>\n     <selectedon>:/control/stop_default</selectedon>:/control/stop_default</iconset>\n   </property>\n   <property name=\"iconSize\">\n    <size>\n     <width>31</width>\n     <height>31</height>\n    </size>\n   </property>\n   <property name=\"autoRaise\">\n    <bool>true</bool>\n   </property>\n  </widget>\n  <widget class=\"MouseHoverButton\" name=\"btnVolume\">\n   <property name=\"geometry\">\n    <rect>\n     <x>150</x>\n     <y>10</y>\n     <width>31</width>\n     <height>31</height>\n    </rect>\n   </property>\n   <property name=\"toolTip\">\n    <string>Mute</string>\n   </property>\n   <property name=\"text\">\n    <string/>\n   </property>\n   <property name=\"icon\">\n    <iconset resource=\"resources/resources.qrc\">\n     <normaloff>:/control/sound_on_default</normaloff>\n     <normalon>:/control/sound_on_clicked</normalon>\n     <disabledoff>:/control/sound_on_default</disabledoff>\n     <disabledon>:/control/sound_on_default</disabledon>\n     <activeoff>:/control/sound_on_hover</activeoff>\n     <activeon>:/control/sound_on_hover</activeon>\n     <selectedoff>:/control/sound_on_default</selectedoff>\n     <selectedon>:/control/sound_on_default</selectedon>:/control/sound_on_default</iconset>\n   </property>\n   <property name=\"iconSize\">\n    <size>\n     <width>31</width>\n     <height>31</height>\n    </size>\n   </property>\n   <property name=\"autoRaise\">\n    <bool>true</bool>\n   </property>\n  </widget>\n  <widget class=\"MouseHoverButton\" name=\"btnBrowser\">\n   <property name=\"geometry\">\n    <rect>\n     <x>108</x>\n     <y>8</y>\n     <width>31</width>\n     <height>31</height>\n    </rect>\n   </property>\n   <property name=\"toolTip\">\n    <string>Browse</string>\n   </property>\n   <property name=\"text\">\n    <string/>\n   </property>\n   <property name=\"icon\">\n    <iconset resource=\"resources/resources.qrc\">\n     <normaloff>:/control/globe_default</normaloff>\n     <normalon>:/control/globe_clicked</normalon>\n     <disabledoff>:/control/globe_default</disabledoff>\n     <disabledon>:/control/globe_default</disabledon>\n     <activeoff>:/control/globe_hover</activeoff>\n     <activeon>:/control/globe_hover</activeon>\n     <selectedoff>:/control/globe_default</selectedoff>\n     <selectedon>:/control/globe_default</selectedon>:/control/globe_default</iconset>\n   </property>\n   <property name=\"iconSize\">\n    <size>\n     <width>31</width>\n     <height>31</height>\n    </size>\n   </property>\n   <property name=\"autoRaise\">\n    <bool>true</bool>\n   </property>\n  </widget>\n  <widget class=\"VolumeProgressBar\" name=\"progressBar\">\n   <property name=\"geometry\">\n    <rect>\n     <x>190</x>\n     <y>15</y>\n     <width>30</width>\n     <height>8</height>\n    </rect>\n   </property>\n   <property name=\"sizePolicy\">\n    <sizepolicy hsizetype=\"Fixed\" vsizetype=\"Fixed\">\n     <horstretch>1</horstretch>\n     <verstretch>0</verstretch>\n    </sizepolicy>\n   </property>\n   <property name=\"minimumSize\">\n    <size>\n     <width>30</width>\n     <height>0</height>\n    </size>\n   </property>\n   <property name=\"maximumSize\">\n    <size>\n     <width>30</width>\n     <height>10</height>\n    </size>\n   </property>\n   <property name=\"baseSize\">\n    <size>\n     <width>30</width>\n     <height>0</height>\n    </size>\n   </property>\n   <property name=\"mouseTracking\">\n    <bool>true</bool>\n   </property>\n   <property name=\"toolTip\">\n    <string>Volume control</string>\n   </property>\n   <property name=\"value\">\n    <number>70</number>\n   </property>\n   <property name=\"textVisible\">\n    <bool>false</bool>\n   </property>\n   <property name=\"format\">\n    <string>%p%</string>\n   </property>\n  </widget>\n  <widget class=\"MouseHoverButton\" name=\"btnPlay\">\n   <property name=\"geometry\">\n    <rect>\n     <x>0</x>\n     <y>8</y>\n     <width>40</width>\n     <height>31</height>\n    </rect>\n   </property>\n   <property name=\"toolTip\">\n    <string>Play</string>\n   </property>\n   <property name=\"text\">\n    <string/>\n   </property>\n   <property name=\"icon\">\n    <iconset resource=\"resources/resources.qrc\">\n     <normaloff>:/control/play_default</normaloff>\n     <normalon>:/control/play_clicked</normalon>\n     <disabledoff>:/control/play_default</disabledoff>\n     <disabledon>:/control/play_default</disabledon>\n     <activeoff>:/control/play_hover</activeoff>\n     <activeon>:/control/play_hover</activeon>\n     <selectedoff>:/control/play_default</selectedoff>\n     <selectedon>:/control/play_default</selectedon>:/control/play_default</iconset>\n   </property>\n   <property name=\"iconSize\">\n    <size>\n     <width>40</width>\n     <height>31</height>\n    </size>\n   </property>\n   <property name=\"autoRaise\">\n    <bool>true</bool>\n   </property>\n  </widget>\n </widget>\n <customwidgets>\n  <customwidget>\n   <class>MouseHoverButton</class>\n   <extends>QToolButton</extends>\n   <header>mousehoverbutton.h</header>\n  </customwidget>\n  <customwidget>\n   <class>VolumeProgressBar</class>\n   <extends>QProgressBar</extends>\n   <header>volumeprogressbar.h</header>\n  </customwidget>\n </customwidgets>\n <resources>\n  <include location=\"resources/resources.qrc\"/>\n </resources>\n <connections/>\n</ui>\n"
  },
  {
    "path": "QtPlayer/videodisplay.cpp",
    "content": "#include \"videodisplay.h\"\n\nVideoDisplay::VideoDisplay() = default;\n\nVideoDisplay::~VideoDisplay()\n{\n    if (m_decoder != nullptr) {\n        m_decoder->setFrameListener(nullptr);\n    }\n}\n\nvoid VideoDisplay::setDecoderObject(FFmpegDecoderWrapper* decoder)\n{\n    Q_ASSERT(decoder != nullptr);\n    if (m_decoder != decoder)\n    {\n        m_decoder = decoder;\n        m_decoder->setFrameListener(this);\n        m_decoder->getFrameDecoder()->SetFrameFormat(\n#ifdef DEVELOPER_OPENGL\n                    IFrameDecoder::PIX_FMT_YUV420P\n#else\n                    IFrameDecoder::PIX_FMT_RGB24\n#endif\n                    , false);\n    }\n}\n\nvoid VideoDisplay::finishedDisplayingFrame(unsigned int generation)\n{\n    m_decoder->finishedDisplayingFrame(generation);\n}\n"
  },
  {
    "path": "QtPlayer/videodisplay.h",
    "content": "#pragma once\n\n#include <QImage>\n#include <QPixmap>\n#include \"ffmpegdecoder.h\"\n\nclass VideoDisplay : public IFrameListener\n{\npublic:\n\tVideoDisplay();\n\t~VideoDisplay() override;\n    void finishedDisplayingFrame(unsigned int generation);\n    void setDecoderObject(FFmpegDecoderWrapper* decoder);\n\n    virtual void showPicture(const QImage& picture) = 0;\n    virtual void showPicture(const QPixmap& picture) = 0;\n\nprotected:\n    FFmpegDecoderWrapper* m_decoder{nullptr};\n};\n"
  },
  {
    "path": "QtPlayer/videoplayer.cpp",
    "content": "#include \"videoplayer.h\"\n#include \"widgetdisplay.h\"\n\n#include <QDebug>\n\nVideoPlayer::VideoPlayer() = default;\n\nVideoPlayer::~VideoPlayer()\n{\n\tdelete m_display;\n}\n\nFFmpegDecoderWrapper* VideoPlayer::getDecoder()\n{\n    return &m_decoder;\n}\n\nVideoDisplay* VideoPlayer::getCurrentDisplay()\n{\n\treturn m_display;\n}\n\nvoid VideoPlayer::setDisplay(VideoDisplay* display)\n{\n\tQ_ASSERT(display);\n    delete m_display;\n\n\tm_display = display;\n    m_decoder.setFrameListener(m_display);\n}\n\nvoid VideoPlayer::setState(VideoState newState)\n{\n\tqDebug() << __FUNCTION__ << \"newState:\" << newState;\n\tm_state = newState;\n}\n"
  },
  {
    "path": "QtPlayer/videoplayer.h",
    "content": "#pragma once\n\n#include \"ffmpegdecoder.h\"\n\n\nclass VideoPlayer\n{\npublic:\n\tenum VideoState\n\t{\n\t\tInitialState,\n\t\tPlaying,\n\t\tPaused,\n\t};\n\n\tVideoPlayer();\n\tvirtual ~VideoPlayer();\n\n    FFmpegDecoderWrapper* getDecoder();\n\tVideoDisplay* getCurrentDisplay();\n\tvirtual void setDisplay(VideoDisplay* display);\n\tVideoState state() const { return m_state; }\n\nprotected:\n\tvoid setState(VideoState newState);\n\nprivate:\n    FFmpegDecoderWrapper m_decoder;\n\tVideoDisplay* m_display{nullptr};\n\tVideoState m_state{InitialState};\n};\n"
  },
  {
    "path": "QtPlayer/videoplayerwidget.cpp",
    "content": "#include \"videoplayerwidget.h\"\n#include \"videowidget.h\"\n#include \"videocontrol.h\"\n#include \"videoprogressbar.h\"\n\n#include <QDesktopServices>\n#include <QResizeEvent>\n#include <QPointer>\n#include <QMessageBox>\n#include <QDebug>\n\nenum { PROGRESSBAR_VISIBLE_HEIGHT = 5 };\n\nVideoPlayerWidget::VideoPlayerWidget(QWidget* parent) :\n\tQFrame(parent)\n\t, m_videoWidget(new VideoWidget(this))\n{\n    connect(getDecoder(), &FFmpegDecoderWrapper::onPlayingFinished, this, &VideoPlayerWidget::onPlayingFinished);\n\n\tsetDisplay(m_videoWidget);\n\tm_videoWidget->installEventFilter(this);\n}\n\nvoid VideoPlayerWidget::setVideoFilename(const QString& fileName)\n{\n\tm_currentFile = fileName;\n}\n\nVideoDisplay* VideoPlayerWidget::getCurrentDisplay()\n{\n\treturn VideoPlayer::getCurrentDisplay();\n}\n\nvoid VideoPlayerWidget::setDefaultPreviewPicture()\n{\n\tm_videoWidget->setDefaultPreviewPicture();\n}\n\nQString VideoPlayerWidget::currentFilename() const\n{\n\treturn m_currentFile;\n}\n\nvoid VideoPlayerWidget::setProgressbar(VideoProgressBar* progressbar)\n{\n\tQ_ASSERT(progressbar);\n\tm_progressBar = progressbar;\n    connect(getDecoder(), &FFmpegDecoderWrapper::onChangedFramePosition, m_progressBar, &VideoProgressBar::displayPlayedProgress);\n\tprogressbar->installEventFilter(this);\n}\n\nvoid VideoPlayerWidget::setControl(VideoControl* controlWidget)\n{\n\tQ_ASSERT(controlWidget);\n\tm_controls = controlWidget;\n\tcontrolWidget->installEventFilter(this);\n}\n\nvoid VideoPlayerWidget::stopVideo(bool showDefaultImage)\n{\n    getDecoder()->close(true);\n}\n\nvoid VideoPlayerWidget::playFile(const QString& fileName)\n{\n\tQ_ASSERT(!fileName.isEmpty());\n\tm_currentFile = fileName;\n    FFmpegDecoderWrapper* decoder = getDecoder();\n\tif (decoder->openFile(m_currentFile))\n    {\n        decoder->play();\n        setState(Playing);\n        m_controls->showPlaybutton(false);\n\n\t\tif (!m_videoWidget->isFullScreen())\n\t\t{\n            updateLayout();\n\t\t}\n\t}\n\telse\n\t{\n\t\tm_progressBar->setDownloadedCounter(0);\n\t\tsetState(InitialState);\n\t\tm_controls->showPlaybutton(true);\n        QMessageBox::information(this, \"Player\", tr(\"File %1 cannot be played.\").arg(fileName));\n\t}\n}\n\nvoid VideoPlayerWidget::pauseVideo()\n{\n\tif (state() == Playing && getDecoder()->pauseResume())\n\t{\n\t\tsetState(Paused);\n\t}\n}\n\nbool VideoPlayerWidget::isPaused()\n{\n\treturn (state() == Paused);\n}\n\nvoid VideoPlayerWidget::seekByPercent(float percent)\n{\n    getDecoder()->seekByPercent(percent);\n}\n\nvoid VideoPlayerWidget::playPauseButtonAction()\n{\n    if (state() == Paused)\n    {\n        m_controls->showPlaybutton(false);\n        resumeVideo();\n    }\n\telse if (state() == Playing)\n\t{\n\t\tm_controls->showPlaybutton(true);\n\t\tpauseVideo();\n\t}\n}\n\nvoid VideoPlayerWidget::resumeVideo()\n{\n\tif (state() == Paused && getDecoder()->pauseResume()) // It actually resumes\n\t{\n\t\tsetState(Playing);\n\t}\n}\n\nvoid VideoPlayerWidget::updateViewOnVideoStop(bool showDefaultImage /* = false*/)\n{\n\tif (m_videoWidget->isFullScreen())\n\t{\n\t\tm_videoWidget->fullScreen(false);\n\t}\n\n\tm_controls->showPlaybutton();\n\n    m_currentFile = QString();\n    m_progressBar->resetProgress();\n\tsetState(InitialState);\n\n\temit fileReleased();\n}\n\nVideoPlayerWidget::~VideoPlayerWidget()\n{\n\tstopVideo();\n    m_videoWidget = nullptr;\n}\n\nvoid VideoPlayerWidget::resizeEvent(QResizeEvent* event)\n{\n\tQ_UNUSED(event);\n\tupdateLayout();\n}\n\nbool VideoPlayerWidget::eventFilter(QObject* object, QEvent* event)\n{\n\tif (event->type() == QEvent::KeyRelease)\n\t{\n\t\tauto* ke = static_cast<QKeyEvent*>(event);\n\t\tif (ke->key() == Qt::Key_Space)\n\t\t{\n\t\t\tplayPauseButtonAction();\n\t\t}\n\t}\n\treturn QFrame::eventFilter(object, event);\n}\n\nvoid VideoPlayerWidget::updateLayout()\n{\n\tint currWidth = width();\n\tint currHeight = height();\n\n\tconst int controlsHeight = m_controls->getHeight();\n\n    int minPlayerHeight = currHeight - controlsHeight;\n\n\tint playerWidth = currWidth;\n\tint yPos = 1;\n    FFmpegDecoderWrapper* dec = getDecoder();\n\tQ_ASSERT(dec != nullptr);\n    if (state() == InitialState)\n\t{\n        double aspectRatio =\n                (m_videoWidget->getPictureSize().height() > 0 && m_videoWidget->getPictureSize().width() >0)\n                ? static_cast<double>(m_videoWidget->getPictureSize().height()) / m_videoWidget->getPictureSize().width()\n                : 0.75;\n\t\tint height = aspectRatio * currWidth;\n\t\t// Display too big: do recalculation\n\t\tif (height > minPlayerHeight)\t// TODO(Usrer): code refactoring\n\t\t{\n\t\t\theight = minPlayerHeight;\n\t\t\tplayerWidth = static_cast<int>(static_cast<double>(minPlayerHeight) / aspectRatio);\n\t\t}\n\n\t\tm_videoWidget->setGeometry(0, yPos, playerWidth, height - PROGRESSBAR_VISIBLE_HEIGHT);\n\t\tyPos += height;\n\n\t\tQImage previewPic = m_videoWidget->startImageButton().scaled(playerWidth, yPos - PROGRESSBAR_VISIBLE_HEIGHT, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);\n\t\tif (m_videoWidget->startImageButton() == m_videoWidget->noPreviewImage())\n\t\t{\n\t\t\tm_videoWidget->showPicture(previewPic);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_videoWidget->updatePlayButton();\n\t\t\tm_videoWidget->showPicture(m_videoWidget->drawPreview(previewPic));\n\t\t}\n\t}\n\telse if (dec->isPlaying())\n\t{\n//#ifdef DEVELOPER_OPENGL\n\t\tQSize pictureSize = QSize(playerWidth, playerWidth);\n        double aspectRatio = m_videoWidget->aspectRatio();\n//#else\n//\t\tQSize pictureSize = dec->getPreferredSize(playerWidth, playerWidth).size();\n//\t\tdouble aspectRatio = (double)pictureSize.height() / pictureSize.width();\n//#endif\n\t\tint playerHeight = pictureSize.width() * aspectRatio;\n\t\t// Display too big: do recalculation\n\t\tif (playerHeight > minPlayerHeight)\n\t\t{\n\t\t\tplayerHeight = minPlayerHeight;\n\t\t\tplayerWidth = static_cast<int>(static_cast<double>(minPlayerHeight) / aspectRatio);\n\t\t}\n\n\t\tif (m_videoWidget->isFullScreen())\n\t\t{\n\t\t\tm_videoWidget->setGeometry(0, 0, currWidth, currHeight);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tm_videoWidget->setGeometry(0, yPos, playerWidth, playerHeight - PROGRESSBAR_VISIBLE_HEIGHT);\n\t\t}\n\t\tyPos += playerHeight;\n\t}\n\n    if (m_progressBar != nullptr)\n    {\n        int progressHeight = m_progressBar->height();\n        m_progressBar->move(0, yPos - (progressHeight + PROGRESSBAR_VISIBLE_HEIGHT) / 2);\n        m_progressBar->resize(playerWidth, progressHeight);\n    }\n\n\tint controlsPos = (playerWidth - m_controls->getWidth()) / 2;\n\tif (controlsPos < 0)\n\t{\n\t\tcontrolsPos = 0;\n\t}\n\tm_controls->move(controlsPos, yPos);\n\tm_controls->resize(m_controls->getWidth(), controlsHeight);\n}\n\nvoid VideoPlayerWidget::exitFullScreen()\n{\n\tonPlayingFinished();\n}\n\nvoid VideoPlayerWidget::onPlayingFinished()\n{\n\tif ((m_videoWidget != nullptr) && m_videoWidget->isFullScreen())\n\t{\n\t\tm_videoWidget->fullScreen(false);\n\t}\n}\n"
  },
  {
    "path": "QtPlayer/videoplayerwidget.h",
    "content": "#pragma once\n\n#include \"mainwindow.h\"\n#include \"videoplayer.h\"\n\n#include <QFrame>\n#include <QPointer>\n\nclass VideoControl;\nclass VideoProgressBar;\nclass VideoWidget;\n\n\nclass VideoPlayerWidget;\n\ninline VideoPlayerWidget* VideoPlayerWidgetInstance()\n{\n    if (auto mainWindow = getMainWindow()) {\n        return mainWindow->getPlayer();\n    }\n    return nullptr;\n}\n\n\nclass VideoPlayerWidget : public QFrame, public VideoPlayer\n{\n\tQ_OBJECT\npublic:\n\texplicit VideoPlayerWidget(QWidget* parent = nullptr);\n\t~VideoPlayerWidget() override;\n\n\tvoid pauseVideo();\n\tvoid resumeVideo();\n\n\tvoid stopVideo(bool showDefaultImage = false);\n\tbool isPaused();\n    void seekByPercent(float percent);\n\n\tVideoDisplay* getCurrentDisplay();\n\tVideoWidget* videoWidget() {return m_videoWidget;}\n\n\tvoid setProgressbar(VideoProgressBar* progressbar);\n\tvoid setControl(VideoControl* controlWidget);\n\n\tvoid setDefaultPreviewPicture();\n\n\tQString currentFilename() const;\n\n    void updateLayout();\n\n\tvoid exitFullScreen();\n\n\tvoid playFile(const QString& fileName);\n\nprotected:\n\tvoid resizeEvent(QResizeEvent* event) override;\n\tbool eventFilter(QObject* object, QEvent* event) override;\n\npublic slots:\n\tvoid playPauseButtonAction();\n\nprivate slots:\n\tvoid setVideoFilename(const QString& fileName);\n\n\tvoid updateViewOnVideoStop(bool showDefaultImage = true);\n\n\tvoid onPlayingFinished();\n\nsignals:\n\tvoid fileReleased();\n\nprivate:\n    friend class VideoWidget;\n\n\tVideoControl* m_controls{nullptr};\n\tVideoProgressBar* m_progressBar{nullptr};\n\tQString m_currentFile;\n\tVideoWidget* m_videoWidget;\n};\n"
  },
  {
    "path": "QtPlayer/videoprogressbar.cpp",
    "content": "#include \"videoprogressbar.h\"\n#include \"ffmpegdecoder.h\"\n#include \"videoplayerwidget.h\"\n#include <QPainter>\n#include <QEvent>\n#include <QMouseEvent>\n#include <QToolTip>\n\n#include <qdrawutil.h>\n#include <algorithm>\n\nVideoProgressBar::VideoProgressBar(QWidget* parent) :\n\tQProgressBar(parent)\n{\n\tm_downloaded = 0;\n\tm_played = 0;\n\n\tsetWindowTitle(\"Video Progress Bar\");\n\tresize(500, 200);\n\tinstallEventFilter(this);\n}\n\nVideoProgressBar::~VideoProgressBar() = default;\n\nvoid VideoProgressBar::paintEvent(QPaintEvent* event)\n{\n\tQ_UNUSED(event)\n\tQPainter painter(this);\n\tQLinearGradient gradient(0, 0, 0, height());\n\n\tint lineheight = height() / 3;\n\tint margintop = (height() - lineheight) / 2;\n\n\t// Draw background line\n\tgradient.setColorAt(0, QColor(67, 67, 67));\n\tgradient.setColorAt(1, QColor(49, 49, 50));\n\tpainter.setBrush(gradient);\n\tpainter.setPen(Qt::NoPen);\n\tpainter.drawRect(0, margintop, width(), lineheight);\n\n\t// Downloaded line\n\tgradient.setColorAt(0, QColor(235, 235, 235));\n\tgradient.setColorAt(1, QColor(207, 213, 217));\n\tpainter.setBrush(gradient);\n\tpainter.drawRect(0, margintop, (static_cast<double>(m_downloaded) / m_scale) * width(), lineheight);\n\n\t// 3 step : playing line\n\tgradient.setColorAt(0, QColor(209, 63, 70));\n\tgradient.setColorAt(1, QColor(177, 10, 11));\n\tpainter.setBrush(gradient);\n\tpainter.drawRect(0, margintop, (static_cast<double>(m_played) / m_scale) * width(), lineheight);\n\n\tQPixmap clicker = QPixmap(\":/images/video_seek_cursor.png\");\n\tpainter.drawPixmap(\n\t\tQRect((m_played / (m_scale - static_cast<double>(clicker.width())*m_scale / (width()))) * width() - 1 - static_cast<double>(clicker.width())*m_played / m_scale * 1.8 , 1, clicker.width(), clicker.height()),\n\t\tclicker,\n\t\tclicker.rect()\n\t);\n}\n\nvoid VideoProgressBar::setDownloadedCounter(int downloaded)\n{\n    downloaded = std::clamp(downloaded, 0, m_scale);\n\n\tif (m_downloaded == downloaded)\n\t{\n\t\treturn;\n\t}\n\n\tm_downloaded = downloaded;\n\n\trepaint();\n}\n\nvoid VideoProgressBar::setPlayedCounter(int played)\n{\n\tif (played < 0)\n\t{\n\t\tplayed = 0;\n\t}\n\n\tif (m_played == played)\n\t{\n\t\treturn;\n\t}\n\n\tm_played = played;\n\n\trepaint();\n}\n\nint VideoProgressBar::getScale() const\n{\n\treturn m_scale;\n}\n\nvoid VideoProgressBar::resetProgress()\n{\n\tm_downloaded = 0;\n\tm_played = 0;\n\trepaint();\n\n\tsetToolTip(QString());\n\tif (underMouse())\n\t{\n\t\tQToolTip::hideText();\n\t}\n}\n\nbool VideoProgressBar::eventFilter(QObject* obj, QEvent* event)\n{\n    //const FFmpegDecoder* decoder = VideoPlayerWidgetInstance()->getDecoder();\n\tQEvent::Type eventType = event->type();\n\tswitch (eventType)\n\t{\n\tcase QEvent::MouseMove:\n\t{\n\t\tauto* mevent = static_cast<QMouseEvent*>(event);\n\t\tfloat percent = (mevent->x() * 1.0) / width();\n\n\t\tif (m_btn_down)\n\t\t{\n            percent = std::clamp(percent, 0.F, 1.F);\n\n\t\t\tif (!m_seekDisabled)\n\t\t\t{\n                VideoPlayerWidgetInstance()->seekByPercent(percent);\n\t\t\t}\n\t\t}\n\t}\n\tbreak;\n\tcase QEvent::MouseButtonPress:\n\t{\n\t\tm_btn_down = true;\n\t}\n\tbreak;\n\tcase QEvent::MouseButtonRelease:\n\t{\n\t\tauto* mevent = static_cast<QMouseEvent*>(event);\n\t\tfloat percent = (mevent->x() * 1.0) / width();\n\n        percent = std::clamp(percent, 0.F, 1.F);\n\n\t\tif (!m_seekDisabled)\n\t\t{\n            VideoPlayerWidgetInstance()->seekByPercent(percent);\n\t\t}\n\t\tm_btn_down = false;\n\t}\n\tbreak;\n\tdefault:;\n\t}\n\n\treturn QWidget::eventFilter(obj, event);\n}\n\n\nvoid VideoProgressBar::displayPlayedProgress(qint64 frame, qint64 total)\n{\n\tint progress = (static_cast<double>(frame) / total) * getScale();\n\tif (!m_seekDisabled)\n\t{\n\t\tsetPlayedCounter(progress);\n\t}\n\telse\n\t{\n\t\tsetPlayedCounter(0);\n\t}\n}\n\nvoid VideoProgressBar::seekingEnable(bool enable /* = true*/)\n{\n\tm_seekDisabled = !enable;\n}\n"
  },
  {
    "path": "QtPlayer/videoprogressbar.h",
    "content": "#pragma once\n\n#include <QProgressBar>\n\nclass VideoProgressBar : public QProgressBar\n{\n\tQ_OBJECT\npublic:\n\texplicit VideoProgressBar(QWidget* parent = nullptr);\n\n\t~VideoProgressBar() override;\n\tint getScale() const;\n\tvoid resetProgress();\n\nprotected:\n\tvoid paintEvent(QPaintEvent* event) override;\n\tbool eventFilter(QObject* obj, QEvent* event) override;\n\nprivate:\n\tint m_downloaded;\n\tint m_played;\n\tint m_scale{1000};\n\tbool m_btn_down{false};\n\tbool m_seekDisabled{false};\n\tqint64 m_downloadedTotalOriginal{0};\npublic slots:\n\tvoid setDownloadedCounter(int downloaded);\n\tvoid setPlayedCounter(int played);\n\tvoid seekingEnable(bool enable = true);\npublic slots:\n\tvoid displayPlayedProgress(qint64 frame, qint64 total);\n};\n"
  },
  {
    "path": "QtPlayer/videowidget.cpp",
    "content": "#include \"videowidget.h\"\n#include \"customdockwidget.h\"\n#include \"videoplayerwidget.h\"\n\n#include <QResizeEvent>\n#include <QPainter>\n#include <QDateTime>\n\n#include <cmath>\n\nnamespace {\n\nQWidget* videoControlWidget()\n{\n    return getMainWindow()->videoControlWidget();\n}\n\nCustomDockWidget* dockWidget()\n{\n    return getMainWindow()->dockWidget();\n}\n\nQWidget* getPlayer()\n{\n    return getMainWindow()->getPlayer();\n}\n\n} // namespace\n\nstatic const int HEIGHT_FIX = 1;\n\n#ifdef DEVELOPER_OPENGL\nVideoWidget::VideoWidget(VideoPlayerWidget* parent) : OpenGLDisplay(parent),\n#else\nVideoWidget::VideoWidget(VideoPlayerWidget* parent) : WidgetDisplay(parent),\n#endif\n\t\n\tm_defPlayButton(\":/images/video___btn_play___default___(94x94).png\"),\n\tm_hoverPlayButton(\":/images/video___btn_play___hover___(94x94).png\"),\n\tm_clickedPlayButton(\":/images/video___btn_play___clicked___(94x94).png\"),\n\tm_selImage(&m_defPlayButton)\n{\n\tm_noPreviewImg = QImage(\":/images/fvd_banner.png\");\n\tsetMouseTracking(true);\n\tsetStyleSheet(\"background: black;\");\n#ifndef DEVELOPER_OPENGL\n\tsetAlignment(Qt::AlignCenter);\n#endif\n\n\tm_cursorTimer.setInterval(1000);\n    connect(&m_cursorTimer, &QTimer::timeout, this, &VideoWidget::onCursorTimer);\n\tm_cursorTimer.start();\n}\n\n\nVideoWidget::~VideoWidget()\n{\n    if (auto videoPlayerWidgetInstance = VideoPlayerWidgetInstance())\n    {\n        videoPlayerWidgetInstance->m_videoWidget = nullptr;\n    }\n}\n\nvoid VideoWidget::setDefaultPreviewPicture()\n{\n\tm_startImgButton = m_noPreviewImg;\n\tm_pictureSize = m_startImgButton.size();\n\n\tVideoPlayerWidgetInstance()->updateLayout();\n\n\tm_fromImage = m_startImgButton;\n\n\tshowPicture(m_startImgButton.scaled(width(), height() + HEIGHT_FIX, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));\n\tsetContentsMargins(0, 0, 0, 0);\n}\n\n\nQPixmap VideoWidget::drawPreview(const QImage& fromImage)\n{\n\tQ_ASSERT(m_selImage);\n\tif (VideoPlayerWidgetInstance()->state() == VideoPlayerWidget::InitialState)\n\t{\n\t\tQPixmap preview_with_button(fromImage.width(), fromImage.height());\n\t\tQPainter painter(&preview_with_button);\n\t\tpainter.drawImage(0, 0, fromImage);\n\t\tpainter.drawImage(fromImage.width() / 2 - m_selImage->width() / 2, fromImage.height() / 2 - m_selImage->height() / 2, *m_selImage);\n\t\tpainter.end();\n\t\treturn preview_with_button;\n\t}\n\treturn QPixmap::fromImage(fromImage);\n}\n\nvoid VideoWidget::hidePlayButton()\n{\n\tshowPicture(m_startImgButton.scaled(width(), height() + HEIGHT_FIX, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));\n}\n\nvoid VideoWidget::getImageFinished(const QImage& image)\n{\n\tm_startImgButton = m_fromImage = image.isNull() ? m_noPreviewImg : image;\n\n\tm_pictureSize = m_startImgButton.size();\n\n\tif (!isFullScreen())\n\t{\n\t\t// This will set image to layout\n\t\tVideoPlayerWidgetInstance()->updateLayout();\n\t}\n}\n\nvoid VideoWidget::showElements()\n{\n\tm_lastMouseTime = QDateTime::currentMSecsSinceEpoch();\n\tsetCursor(Qt::ArrowCursor);\n    videoControlWidget()->show();\n}\n\nvoid VideoWidget::hideElements()\n{\n\tsetCursor(Qt::BlankCursor);\n    videoControlWidget()->hide();\n}\n\nvoid VideoWidget::keyPressEvent(QKeyEvent* event)\n{\n\tshowElements();\n\t// Full screen exiting\n\tif (((event->key() == Qt::Key_Return  || event->key() == Qt::Key_Enter) && (event->modifiers() & Qt::AltModifier))\n\t\t\t|| event->key() == Qt::Key_Escape)\n\t{\n\t\tif (isFullScreen())\n\t\t{\n\t\t\tfullScreen(false);\n\t\t}\n\t}\n}\n\nvoid VideoWidget::mousePressEvent(QMouseEvent* event)\n{\n\tshowElements();\n\n    if (event->button() == Qt::LeftButton && VideoPlayerWidgetInstance()->state() == VideoPlayerWidget::InitialState && pointInButton(event->pos()))\n\t{\n\t\tm_isMousePressed = true;\n\n\t\tm_selImage = &m_clickedPlayButton;\n\t\tm_startImgButton = m_fromImage;\n\n\t\tm_pictureSize = m_startImgButton.size();\n\t\tshowPicture(drawPreview(m_startImgButton.scaled(width(), height() + HEIGHT_FIX, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));\n\t}\n}\n\nvoid VideoWidget::mouseReleaseEvent(QMouseEvent* event)\n{\n\tif (event->button() == Qt::LeftButton)\n\t{\n\t\tshowElements();\n\n\t\tVideoPlayerWidget::VideoState state = VideoPlayerWidgetInstance()->state();\n\n\t\tif (state == VideoPlayerWidget::Paused || state == VideoPlayerWidget::Playing)\n\t\t{\n\t\t\tVideoPlayerWidgetInstance()->playPauseButtonAction();\n\t\t}\n\t\telse if (m_isMousePressed)\n\t\t{\n\t\t\tm_isMousePressed = false;\n\n\t\t\tm_selImage = pointInButton(event->pos()) ? &m_hoverPlayButton : &m_defPlayButton;\n\t\t\tm_startImgButton = m_fromImage;\n\n\t\t\tm_pictureSize = m_startImgButton.size();\n\n\t\t\tif (m_selImage == &m_hoverPlayButton && state == VideoPlayerWidget::InitialState)\n\t\t\t{\n\t\t\t\tVideoPlayerWidgetInstance()->playPauseButtonAction();\n\t\t\t}\n\t\t}\n\t}\n\telse if (event->button() == Qt::MiddleButton)\n\t{\n        if (isFullScreen()) {\n            fullScreen(false);\n        } else {\n            dockWidget()->setVisibilityState(CustomDockWidget::FullScreen);\n        }\n\t}\n}\n\nvoid VideoWidget::mouseMoveEvent(QMouseEvent* event)\n{\n\tshowElements();\n\n    if (VideoPlayerWidgetInstance()->state() == VideoPlayerWidget::InitialState)\n\t{\n\t\tQImage* selImage = m_isMousePressed ? &m_clickedPlayButton : (pointInButton(event->pos()) ? &m_hoverPlayButton : &m_defPlayButton);\n\t\tif (m_selImage != selImage)\n\t\t{\n\t\t\tm_selImage = selImage;\n\t\t\tm_startImgButton = m_fromImage;\n\n\t\t\tm_pictureSize = m_startImgButton.size();\n\t\t\tshowPicture(drawPreview(m_startImgButton.scaled(width(), height() + HEIGHT_FIX, Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));\n\t\t}\n\t}\n}\n\nvoid VideoWidget::wheelEvent(QWheelEvent* event)\n{\n\tshowElements();\n\tVideoPlayerWidgetInstance()->wheelEvent(event);\n}\n\nbool VideoWidget::pointInButton(const QPoint& point)\n{\n\tQPoint centerPoint(width() / 2, height() / 2);\n\n\tif (point.x() >= centerPoint.x() - m_playBtnRadius && point.x() <= centerPoint.x() + m_playBtnRadius &&\n\t\t\tpoint.y() >= centerPoint.y() - m_playBtnRadius && point.y() <= centerPoint.y() + m_playBtnRadius)\n\t{\n        return std::hypot(centerPoint.x() - point.x(), centerPoint.y() - point.y()) < m_playBtnRadius;\n\t}\n\treturn false;\n}\n\nvoid VideoWidget::updatePlayButton()\n{\n\tif (VideoPlayerWidgetInstance()->state() == VideoPlayerWidget::InitialState)\n\t{\n\t\tm_selImage = pointInButton(mapFromGlobal(QCursor::pos())) ? &m_hoverPlayButton : &m_defPlayButton;\n\t}\n}\n\nvoid VideoWidget::fullScreen(bool isEnable)\n{\n\tif (isEnable)\n\t{\n        setWindowFlags(Qt::Window);\n\t\tsetContentsMargins(0, 0, 0, 0);\n\n#ifdef Q_OS_LINUX\n\t\tQ_ASSERT(!m_resizeIndicator);\n\t\tm_resizeIndicator = true;\n#endif\n\n\t\tshowFullScreen();\n\n#ifndef Q_OS_LINUX\n\t\tfullScreenProcess();\n#endif\n\t}\n\telse\n\t{\n        setWindowFlags(Qt::SubWindow);\n\t\tshowNormal();\n\t\tVideoPlayerWidgetInstance()->updateLayout();\n\t\temit leaveFullScreen();\n\n        QWidget* videoControl = videoControlWidget();\n        videoControl->setParent(getPlayer(), Qt::SubWindow);\n\t\tvideoControl->lower();\n\t\tvideoControl->show();\n\t}\n}\n\nvoid VideoWidget::fullScreenProcess()\n{\n\tif (VideoPlayerWidget::InitialState == VideoPlayerWidgetInstance()->state())\n\t{\n\t\tupdatePlayButton();\n        //setPreviewPicture(VideoPlayerWidgetInstance()->entity());\n\t}\n\n    QWidget* videoControl = videoControlWidget();\n    videoControl->setParent(nullptr, Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);\n\tvideoControl->setAttribute(Qt::WA_TranslucentBackground);\n\tvideoControl->move(this->width() / 2 - videoControl->width() / 2, this->height() - videoControl->height() - 20);\n\tvideoControl->show();\n\t//auto* spinner = findChild<QWidget*>(\"bufferingSpinner\");\n\t//Q_ASSERT(spinner);\n\t//spinner->resize(this->width(), this->height());\n}\n\nvoid VideoWidget::resizeEvent(QResizeEvent* event)\n{\n#ifdef Q_OS_LINUX\n\tif (m_resizeIndicator)\n\t{\n\t\tfullScreenProcess();\n\t\tm_resizeIndicator = false;\n\t}\n#endif\n\t// FIXME: OpenGL full support\n#ifdef DEVELOPER_OPENGL\n\tOpenGLDisplay::resizeEvent(event);\n#endif\n}\n\n#ifndef DEVELOPER_OPENGL\nvoid VideoWidget::currentDisplay(unsigned int generation)\n{\n    WidgetDisplay::currentDisplay(generation);\n\tm_originalFrame = *pixmap();\n}\n#endif\n\nvoid VideoWidget::onCursorTimer()\n{\n\tif (isFullScreen() && (QDateTime::currentMSecsSinceEpoch() - m_lastMouseTime > 2000))\n\t{\n\t\thideElements();\n\t}\n}\n\nVideoPlayerWidget* VideoWidget::VideoPlayerWidgetInstance()\n{\n    return static_cast<VideoPlayerWidget*>(parent());\n}\n"
  },
  {
    "path": "QtPlayer/videowidget.h",
    "content": "#pragma once\n\n#include <QImage>\n#include <QRegion>\n#include <QTimer>\n\n#ifdef DEVELOPER_OPENGL\n#include \"opengldisplay.h\"\n#else\n#include \"widgetdisplay.h\"\n#endif\n\nclass VideoPlayerWidget;\n\n// FIXME: OpenGL full support\n#ifdef DEVELOPER_OPENGL\nclass VideoWidget : public OpenGLDisplay\n#else\nclass VideoWidget : public WidgetDisplay\n#endif\n{\n\tQ_OBJECT\n\tQ_PROPERTY(QImage m_noPreviewImg READ noPreviewImage WRITE setNoPreviewImage);\npublic:\n\texplicit VideoWidget(VideoPlayerWidget* parent = nullptr);\n\t~VideoWidget() override;\n\n\tvoid setDefaultPreviewPicture();\n\tQSize getPictureSize() const { return m_pictureSize; }\n\tQPixmap originalFrame() const { return m_originalFrame; }\n\tQImage startImageButton() const { return m_startImgButton; }\n\n\tQImage noPreviewImage() const { return m_noPreviewImg; }\n\tvoid setNoPreviewImage(const QImage& noImage) { m_noPreviewImg = noImage; }\n\n\tQPixmap drawPreview(const QImage& fromImage);\n\tvoid hidePlayButton();\n\n\tvoid updatePlayButton();\n\nprotected:\n\tvoid keyPressEvent(QKeyEvent* event) override;\n\n\tvoid mousePressEvent(QMouseEvent* event) override;\n\tvoid mouseReleaseEvent(QMouseEvent* event) override;\n\tvoid mouseMoveEvent(QMouseEvent* event) override;\n\tvoid wheelEvent(QWheelEvent* event) override;\n\tvoid resizeEvent(QResizeEvent* event) override;\n\n    VideoPlayerWidget* VideoPlayerWidgetInstance();\n\n\tQImage m_startImgButton;\n\tQImage m_noPreviewImg;\n\tQPixmap m_originalFrame;\n\nprivate:\n\tbool m_playIndicator{false};\n\tQSize m_pictureSize;\n\tQImage m_defPlayButton, m_hoverPlayButton, m_clickedPlayButton;\n\tQImage* m_selImage;\n\tQImage m_fromImage;\n\tbool m_isMousePressed{false};\n\tconst int m_playBtnRadius{29};\n#ifdef Q_OS_LINUX\n    bool m_resizeIndicator = false;\n#endif\n\n\tqint64 m_lastMouseTime{0};\n\n\tQTimer m_cursorTimer;\n\n\tbool pointInButton(const QPoint& point);\n\n\tvoid showElements();\n\tvoid hideElements();\n\npublic Q_SLOTS:\n\tvoid fullScreen(bool isEnable = true);\n\nprotected Q_SLOTS:\n#ifndef DEVELOPER_OPENGL\n    virtual void currentDisplay(unsigned int generation) override;\n#endif\n\nprivate Q_SLOTS:\n\tvoid getImageFinished(const QImage& image);\n\tvoid onCursorTimer();\n\tvoid fullScreenProcess();\nQ_SIGNALS:\n\tvoid leaveFullScreen();\n\tvoid mouseClicked();\n};\n"
  },
  {
    "path": "QtPlayer/volumeprogressbar.cpp",
    "content": "#include \"volumeprogressbar.h\"\n\n#include <QPainter>\n\nVolumeProgressBar::VolumeProgressBar(QWidget* parent) : QProgressBar(parent),\n\tm_borderBrush(QColor(101, 105, 108)),\n\tm_backBrush(QColor(66, 66, 66)),\n\tm_fillBorderBrush(QColor(176, 180, 183)),\n\tm_fillBrush(QColor(255, 255, 255))\n{\n}\n\nVolumeProgressBar::~VolumeProgressBar() = default;\n\nvoid VolumeProgressBar::paintEvent(QPaintEvent* event)\n{\n\tQ_UNUSED(event)\n\tQPainter painter(this);\n\n\tpainter.fillRect(0, 0, width(), height(), m_borderBrush);\n\tpainter.fillRect(1, 1, width() - 2, height() - 2, m_backBrush);\n\n\tint filledWidth = static_cast<int>(width() / 100.0 * value());\n\n\tpainter.fillRect(0, 0, filledWidth, height(), m_fillBorderBrush);\n\tif (filledWidth > 1)\n\t{\n\t\tpainter.fillRect(1, 1, filledWidth - 2, height() - 2, m_fillBrush);\n\t}\n}\n"
  },
  {
    "path": "QtPlayer/volumeprogressbar.h",
    "content": "#pragma once\n\n#include <QProgressBar>\n\nclass VolumeProgressBar : public QProgressBar\n{\n\tQ_OBJECT\npublic:\n\tVolumeProgressBar(QWidget* parent);\n\t~VolumeProgressBar() override;\nprotected:\n\tvoid paintEvent(QPaintEvent* event) override;\n\nprivate:\n\tQBrush m_borderBrush, m_backBrush;\n\tQBrush m_fillBorderBrush, m_fillBrush;\n};\n"
  },
  {
    "path": "QtPlayer/widgetdisplay.cpp",
    "content": "#include \"widgetdisplay.h\"\n\n#include <QDebug>\n\n#include <utility>\n\nWidgetDisplay::WidgetDisplay(QWidget* parent) : QLabel(parent)\n{\n    setScaledContents(true);\n    connect(this, &WidgetDisplay::display, this, &WidgetDisplay::currentDisplay);\n}\n\nvoid WidgetDisplay::currentDisplay(unsigned int generation)\n{\n    m_display = QPixmap::fromImage(m_image);\n    setPixmap(m_display);\n\n    finishedDisplayingFrame(generation);\n}\n\n\nvoid WidgetDisplay::showPicture(const QImage& picture)\n{\n\tshowPicture(QPixmap::fromImage(picture));\n}\n\nvoid WidgetDisplay::showPicture(const QPixmap& picture)\n{\n\tsetPixmap(picture);\n}\n\n\nvoid WidgetDisplay::updateFrame(IFrameDecoder* decoder, unsigned int generation)\n{\n    FrameRenderingData data;\n    if (!decoder->getFrameRenderingData(&data))\n    {\n        return;\n    }\n\n    m_aspectRatio = float(data.height) / data.width;\n\n    m_image = QImage(data.image[0], data.width, data.height, data.pitch[0], QImage::Format_RGB888);\n}\n\nvoid WidgetDisplay::drawFrame(IFrameDecoder* decoder, unsigned int generation)\n{\n    emit display(generation);\n}\n\nvoid WidgetDisplay::decoderClosing()\n{\n}\n"
  },
  {
    "path": "QtPlayer/widgetdisplay.h",
    "content": "#pragma once\n\n#include \"videodisplay.h\"\n\n#include <QLabel>\n#include <QPixmap>\n#include <QImage>\n\nclass WidgetDisplay : public QLabel, public VideoDisplay\n{\n\tQ_OBJECT\npublic:\n\tWidgetDisplay(QWidget* parent = nullptr);\n    ~WidgetDisplay() override = default;\n\n\tvoid showPicture(const QImage& picture) override;\n\tvoid showPicture(const QPixmap& picture) override;\n\n    // decoder->finishedDisplayingFrame() must be called\n    void updateFrame(IFrameDecoder* decoder, unsigned int generation) override;\n    void drawFrame(IFrameDecoder* decoder, unsigned int generation) override;\n    void decoderClosing() override;\n\n    float aspectRatio() const { return m_aspectRatio; }\n\nprotected:\n\tQImage m_image;\n\tQPixmap m_display;\n    float m_aspectRatio { 0.75F };\n\nprotected slots:\n    virtual void currentDisplay(unsigned int generation);\nsignals:\n    void display(unsigned int generation);\n};\n"
  },
  {
    "path": "README.md",
    "content": "# ℉ℲmpegPlayer\n\nA 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: \n- Basic Playback Controls: Play/Pause, Stop.\n- Next/Previous Frame: Step through the video one frame at a time during pause.\n- Speed Change: Increase or decrease the playback speed without altering the pitch of the audio.\n- Separate Video and Audio Inputs: Ability to load and play video and audio from separate sources.\n- Audio Track Selection: Choose between different audio tracks if available.\n- Fragment Selection for Export: Mark in and out points to select a part of the video for exporting.\n- Repeated Playing: Loop the entire video/playlist or selected fragment continuously.\n- Subtitles: Load and display subtitle files in various formats.\n- Super Resolution: Enhance the resolution of the video using upscaling techniques.\n- Codec Support: Compatibility with a wide range of video and audio codecs.\n- Streaming Support: Ability to stream video from online sources.\n\n[Semi transparent, click through full screen mode introduced.](https://bit.ly/2JLTbQn) It is invokable by holding ctrl+shift while pressing full screen button.\n\n## Getting Started\n\nThese instructions will get you a copy of the project up and running on your local machine for development and testing purposes.\n\n### Prerequisites\n\n\n- Visual Studio 2017 or higher.\n- vcpkg.\n\n### Installing\n\nBe sure to download git submodules.\n\nTo get a development env running:\n\nInstall vcpkg from https://github.com/Microsoft/vcpkg.\n```\n.\\vcpkg integrate install\n```\n\nInstall Boost, FFmpeg, OpenCV etc. Details can be found in .github/workflows/msbuild.yml.\n\nCreate ./Directory.Build.props file in the project folder. It contents depend on you environment, for example:\n```\n<Project>\n  <PropertyGroup>\n    <WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion>\n    <TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>\n    <PlatformToolset>v143</PlatformToolset>\n  </PropertyGroup>\n</Project>\n```\n\nYouTube 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: Direct‑IP no‑SNI Host‑Override CDN‑Pinning Mode. You can do without SNI by using the IP address in the URL and the Host header to identify the content.\n\nThe 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.\n\nJust 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\n\nTiny demos here: https://www.youtube.com/watch?v=dySA4yEGdEc https://www.youtube.com/watch?v=t5iW2ZsEzrA\n\nTip: 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.\n\nPlease 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.\n\nNote that the FFmpeg patch speeds up HEVC decoding without GPU support by ~10%:\n\n![image](https://user-images.githubusercontent.com/11851670/171165625-3a111046-672c-4a75-8184-c91fde994e00.png)\n\n\n### 🎬 Video Conversion Script Generation\nThis feature generates and runs a batch script that converts selected video files into a format compatible with basic players. The script adapts dynamically based on playback settings and optional media inputs.\n\n#### 🔧 Controlled via Menu Options:\nFile → Convert Videos into Compatible Format Triggers the generation and running of a conversion script using FFmpeg. The script includes commands to re-encode or copy video, audio, and subtitle streams based on compatibility and user preferences.\n\nFile → Autoplay When enabled, the script processes a sequence of video files for automatic conversion. If combined with Looping, the entire sequence is included. If Looping is disabled, only the current and following files are processed.\n\nFile → Looping When Autoplay is disabled, this option includes both the current file and its predecessors in the conversion script. When Autoplay is enabled, it loops through the entire detected sequence of files.\n\nAudio / Video → Open Audio File... Allows users to specify a separate audio file to be merged with the video during conversion. If provided, the script maps video from the original files and audio from the separate files.\n\nAudio / Video → Open Subtitles File... Enables users to attach external subtitle files. These are converted to UTF-8 encoding using ToUTF8.exe and saved alongside the converted videos.\n\n#### 🛠️ Conversion Details:\nUses FFmpeg for media processing.\n\nSelects codecs based on compatibility:\n\nlibx264 for video re-encoding if needed\n\naac for audio if separate or incompatible\n\nCopies subtitle streams when available\n\nOutputs converted files to the specified folder, preserving original filenames.\n\n### Bonus tip\n\nPlaying 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).\n\n![redline](https://user-images.githubusercontent.com/11851670/184552270-73cb8ba4-31f7-47f2-9f50-2b4ceae601e7.gif)\n"
  },
  {
    "path": "Setup/Setup.vdproj",
    "content": "﻿\"DeployProject\"\n{\n\"VSVersion\" = \"3:800\"\n\"ProjectType\" = \"8:{978C614F-708E-4E1A-B201-565925725DBA}\"\n\"IsWebType\" = \"8:FALSE\"\n\"ProjectName\" = \"8:Setup\"\n\"LanguageId\" = \"3:1033\"\n\"CodePage\" = \"3:1252\"\n\"UILanguageId\" = \"3:1033\"\n\"SccProjectName\" = \"8:\"\n\"SccLocalPath\" = \"8:\"\n\"SccAuxPath\" = \"8:\"\n\"SccProvider\" = \"8:\"\n\"BackwardsCompatibleGUIDGeneration\" = \"8:TRUE\"\n    \"Hierarchy\"\n    {\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_02EFEE03BFE64741B0ABE34B02FC32B5\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_04D9482C98764C51AD4E4D730BAEBE29\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_13D05759FE0A4D95A0231F4083F018C4\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_195C5150B8964F18BE6B37EC32F0A6A2\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_1ABC4268EB654842AFAAD1EC6895A7BA\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_1BB4844D47E14A15B89CF19C542161BB\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_1E65B5DFF0DC498E88CA9D3A7C275D76\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_1F243CD6EC02496B996FBE37FD926E0C\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_264B785039E04289B2A9C0F511AD4551\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_277BDF4042FB4CACAB6E1AB94081D4DA\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_28ED1968ACAD4AAC8B67914CE9F9DA96\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_3262A9A7818C4E61A47966A1AC635C9D\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_3287D5542CEB463FBCF4C232B67F1661\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_432363CD76D0480AA7084E8FF9F2BE71\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_4E1B2E066177453BAA56F6A639DA8C91\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_5248F3DEC0F84A5EA1E49E4228FC507F\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_5661D94E79A44B658C8B5D3D6144F5EA\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_5A15AAA6BD1C4EB5AF34273674A620C9\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_5AEE0FDF644E421AA8CE0C416041E22E\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_5F83FC91573A48E4942BBFA02E16470E\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_6B047B7A63CC46B895F0CF653C4202FD\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_773E956ED5734071898B809DF7A09F5C\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_78A6F9F7FFB14C2681C7884E42D8F58A\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_7BBE6F8C77DD46679E86F836865E5268\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_7CFE85030EA24C6DB5A69D7E9D4B9870\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_7EAF2BD4D7C6410AA00673E7A387C976\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_81363E05C5EF41ACA5813F69543E574D\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_854599C408B14066937C40F97C68BD97\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_8E7646220BFC46EEBA194DECA90226DA\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_966194489C5E48A59EDB67DA6102C198\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_96D017BD77B34DDDABD27B278D0313EF\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_99FE9F86BECE469DAF1A2E8A801A82E1\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_9FE3E71BA9214645891A4C52B44EC846\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_A4B43CDF9CA54C19AF7D23DB37A100AC\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_B046520A3F94442E894F11443DE3C515\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_BB3F2FE2B1344C3A89B5586F5E476566\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_CFF418461B324683A7ACE56113EC015D\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_D67C2908BF6B4AB2806D3E5701BDF09A\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_E36BE16F84CF4B1F8F13230F495EB066\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_E6740841F93C44CCB118D19E99E2C1D6\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n        \"Entry\"\n        {\n        \"MsmKey\" = \"8:_FA750DBCBC084FE991EDD407C9629097\"\n        \"OwnerKey\" = \"8:_UNDEFINED\"\n        \"MsmSig\" = \"8:_UNDEFINED\"\n        }\n    }\n    \"Configurations\"\n    {\n        \"Debug\"\n        {\n        \"DisplayName\" = \"8:Debug\"\n        \"IsDebugOnly\" = \"11:TRUE\"\n        \"IsReleaseOnly\" = \"11:FALSE\"\n        \"OutputFilename\" = \"8:Debug\\\\FFmpegPlayerSetup.msi\"\n        \"PackageFilesAs\" = \"3:2\"\n        \"PackageFileSize\" = \"3:-2147483648\"\n        \"CabType\" = \"3:1\"\n        \"Compression\" = \"3:2\"\n        \"SignOutput\" = \"11:FALSE\"\n        \"CertificateFile\" = \"8:\"\n        \"PrivateKeyFile\" = \"8:\"\n        \"TimeStampServer\" = \"8:\"\n        \"InstallerBootstrapper\" = \"3:2\"\n            \"BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}\"\n            {\n            \"Enabled\" = \"11:TRUE\"\n            \"PromptEnabled\" = \"11:TRUE\"\n            \"PrerequisitesLocation\" = \"2:1\"\n            \"Url\" = \"8:\"\n            \"ComponentsUrl\" = \"8:\"\n                \"Items\"\n                {\n                    \"{EDC2488A-8267-493A-A98E-7D9C3B36CDF3}:.NETFramework,Version=v4.5\"\n                    {\n                    \"Name\" = \"8:Microsoft .NET Framework 4.5 (x86 and x64)\"\n                    \"ProductCode\" = \"8:.NETFramework,Version=v4.5\"\n                    }\n                }\n            }\n        }\n        \"Release\"\n        {\n        \"DisplayName\" = \"8:Release\"\n        \"IsDebugOnly\" = \"11:FALSE\"\n        \"IsReleaseOnly\" = \"11:TRUE\"\n        \"OutputFilename\" = \"8:Release\\\\FFmpegPlayerSetup.msi\"\n        \"PackageFilesAs\" = \"3:2\"\n        \"PackageFileSize\" = \"3:-2147483648\"\n        \"CabType\" = \"3:1\"\n        \"Compression\" = \"3:2\"\n        \"SignOutput\" = \"11:FALSE\"\n        \"CertificateFile\" = \"8:\"\n        \"PrivateKeyFile\" = \"8:\"\n        \"TimeStampServer\" = \"8:\"\n        \"InstallerBootstrapper\" = \"3:2\"\n            \"BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}\"\n            {\n            \"Enabled\" = \"11:TRUE\"\n            \"PromptEnabled\" = \"11:TRUE\"\n            \"PrerequisitesLocation\" = \"2:1\"\n            \"Url\" = \"8:\"\n            \"ComponentsUrl\" = \"8:\"\n                \"Items\"\n                {\n                }\n            }\n        }\n    }\n    \"Deployable\"\n    {\n        \"CustomAction\"\n        {\n        }\n        \"DefaultFeature\"\n        {\n        \"Name\" = \"8:DefaultFeature\"\n        \"Title\" = \"8:\"\n        \"Description\" = \"8:\"\n        }\n        \"ExternalPersistence\"\n        {\n            \"LaunchCondition\"\n            {\n            }\n        }\n        \"File\"\n        {\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_04D9482C98764C51AD4E4D730BAEBE29\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_sqlite3.pyd\"\n            \"TargetName\" = \"8:_sqlite3.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_195C5150B8964F18BE6B37EC32F0A6A2\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_ssl.pyd\"\n            \"TargetName\" = \"8:_ssl.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1ABC4268EB654842AFAAD1EC6895A7BA\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_uuid.pyd\"\n            \"TargetName\" = \"8:_uuid.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1BB4844D47E14A15B89CF19C542161BB\"\n            {\n            \"SourcePath\" = \"8:..\\\\edit_git_subst_cfg.cmd\"\n            \"TargetName\" = \"8:edit_git_subst_cfg.cmd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1E65B5DFF0DC498E88CA9D3A7C275D76\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_hashlib.pyd\"\n            \"TargetName\" = \"8:_hashlib.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_1F243CD6EC02496B996FBE37FD926E0C\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_zoneinfo.pyd\"\n            \"TargetName\" = \"8:_zoneinfo.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_264B785039E04289B2A9C0F511AD4551\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_elementtree.pyd\"\n            \"TargetName\" = \"8:_elementtree.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_277BDF4042FB4CACAB6E1AB94081D4DA\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\unicodedata.pyd\"\n            \"TargetName\" = \"8:unicodedata.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_28ED1968ACAD4AAC8B67914CE9F9DA96\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\python.cat\"\n            \"TargetName\" = \"8:python.cat\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A7818C4E61A47966A1AC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\ffmpeg.exe\"\n            \"TargetName\" = \"8:ffmpeg.exe\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A7828C4E61A47966A2AC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\avutil-56.dll\"\n            \"TargetName\" = \"8:avutil-56.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A7838C4E61A47966A3AC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\swscale-5.dll\"\n            \"TargetName\" = \"8:swscale-5.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A7848C4E61A47966A4AC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\swresample-3.dll\"\n            \"TargetName\" = \"8:swresample-3.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A7858C4E61A47966A5AC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\postproc-55.dll\"\n            \"TargetName\" = \"8:postproc-55.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A7868C4E61A47966A6AC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\avresample-4.dll\"\n            \"TargetName\" = \"8:avresample-4.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A7878C4E61A47966A7AC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\avcodec-58.dll\"\n            \"TargetName\" = \"8:avcodec-58.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A7888C4E61A47966A8AC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\avformat-58.dll\"\n            \"TargetName\" = \"8:avformat-58.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A7898C4E61A47966A9AC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\avfilter-7.dll\"\n            \"TargetName\" = \"8:avfilter-7.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A78A8C4E61A47966AAAC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\avdevice-58.dll\"\n            \"TargetName\" = \"8:avdevice-58.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A78B8C4E61A47966ABAC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\libx264-157.dll\"\n            \"TargetName\" = \"8:libx264-157.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A78C8C4E61A47966ACAC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\webp.dll\"\n            \"TargetName\" = \"8:webp.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3262A9A78D8C4E61A47966ADAC635C9D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\vcpkg\\\\installed\\\\x86-windows\\\\tools\\\\ffmpeg\\\\zlib1.dll\"\n            \"TargetName\" = \"8:zlib1.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3287D5542CEB463FBCF4C232B67F1661\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_decimal.pyd\"\n            \"TargetName\" = \"8:_decimal.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_432363CD76D0480AA7084E8FF9F2BE71\"\n            {\n            \"SourcePath\" = \"8:..\\\\remove_youtube_transcript_api.cmd\"\n            \"TargetName\" = \"8:remove_youtube_transcript_api.cmd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5248F3DEC0F84A5EA1E49E4228FC507F\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\python39.zip\"\n            \"TargetName\" = \"8:python39.zip\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5661D94E79A44B658C8B5D3D6144F5EA\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\python.exe\"\n            \"TargetName\" = \"8:python.exe\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5A15AAA6BD1C4EB5AF34273674A620C9\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\pythonw.exe\"\n            \"TargetName\" = \"8:pythonw.exe\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5AEE0FDF644E421AA8CE0C416041E22E\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_msi.pyd\"\n            \"TargetName\" = \"8:_msi.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5F83FC91573A48E4942BBFA02E16470E\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\winsound.pyd\"\n            \"TargetName\" = \"8:winsound.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_6B047B7A63CC46B895F0CF653C4202FD\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_overlapped.pyd\"\n            \"TargetName\" = \"8:_overlapped.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_773E956ED5734071898B809DF7A09F5C\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\pyexpat.pyd\"\n            \"TargetName\" = \"8:pyexpat.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_78A6F9F7FFB14C2681C7884E42D8F58A\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_lzma.pyd\"\n            \"TargetName\" = \"8:_lzma.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7BBE6F8C77DD46679E86F836865E5268\"\n            {\n            \"SourcePath\" = \"8:..\\\\Player\\\\res\\\\Player.ico\"\n            \"TargetName\" = \"8:Player.ico\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7CFE85030EA24C6DB5A69D7E9D4B9870\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_bz2.pyd\"\n            \"TargetName\" = \"8:_bz2.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_7EAF2BD4D7C6410AA00673E7A387C976\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\libcrypto-1_1.dll\"\n            \"TargetName\" = \"8:libcrypto-1_1.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_81363E05C5EF41ACA5813F69543E574D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\sqlite3.dll\"\n            \"TargetName\" = \"8:sqlite3.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_854599C408B14066937C40F97C68BD97\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\select.pyd\"\n            \"TargetName\" = \"8:select.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_8E7646220BFC46EEBA194DECA90226DA\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\python39._pth\"\n            \"TargetName\" = \"8:python39._pth\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_966194489C5E48A59EDB67DA6102C198\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_ctypes.pyd\"\n            \"TargetName\" = \"8:_ctypes.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_96D017BD77B34DDDABD27B278D0313EF\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\libffi-7.dll\"\n            \"TargetName\" = \"8:libffi-7.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_99FE9F86BECE469DAF1A2E8A801A82E1\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_asyncio.pyd\"\n            \"TargetName\" = \"8:_asyncio.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_9FE3E71BA9214645891A4C52B44EC846\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\libssl-1_1.dll\"\n            \"TargetName\" = \"8:libssl-1_1.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_A4B43CDF9CA54C19AF7D23DB37A100AC\"\n            {\n            \"SourcePath\" = \"8:..\\\\remove_pytube.cmd\"\n            \"TargetName\" = \"8:remove_pytube.cmd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_B046520A3F94442E894F11443DE3C515\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_socket.pyd\"\n            \"TargetName\" = \"8:_socket.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_BB3F2FE2B1344C3A89B5586F5E476566\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\LICENSE.txt\"\n            \"TargetName\" = \"8:LICENSE.txt\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_CFF418461B324683A7ACE56113EC015D\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\python3.dll\"\n            \"TargetName\" = \"8:python3.dll\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D67C2908BF6B4AB2806D3E5701BDF09A\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_multiprocessing.pyd\"\n            \"TargetName\" = \"8:_multiprocessing.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_E6740841F93C44CCB118D19E99E2C1D6\"\n            {\n            \"SourcePath\" = \"8:C:\\\\python-embed-win32\\\\_queue.pyd\"\n            \"TargetName\" = \"8:_queue.pyd\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            }\n        }\n        \"FileType\"\n        {\n        }\n        \"Folder\"\n        {\n            \"{1525181F-901A-416C-8A58-119130FE478E}:_164318547FB24CA28F6F77C529476D36\"\n            {\n            \"Name\" = \"8:#1916\"\n            \"AlwaysCreate\" = \"11:FALSE\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Property\" = \"8:DesktopFolder\"\n                \"Folders\"\n                {\n                }\n            }\n            \"{1525181F-901A-416C-8A58-119130FE478E}:_575FB8B12F0B4A8FA84C53016FE10EE5\"\n            {\n            \"Name\" = \"8:#1919\"\n            \"AlwaysCreate\" = \"11:FALSE\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Property\" = \"8:ProgramMenuFolder\"\n                \"Folders\"\n                {\n                    \"{9EF0B969-E518-4E46-987F-47570745A589}:_9B328E46D8A9465692C2C0A26ECD0EB4\"\n                    {\n                    \"Name\" = \"8:FFmpeg Player\"\n                    \"AlwaysCreate\" = \"11:FALSE\"\n                    \"Condition\" = \"8:\"\n                    \"Transitive\" = \"11:FALSE\"\n                    \"Property\" = \"8:_E74CB00121364B60BD4599770E8BB2F0\"\n                        \"Folders\"\n                        {\n                        }\n                    }\n                }\n            }\n            \"{3C67513D-01DD-4637-8A68-80971EB9504F}:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            {\n            \"DefaultLocation\" = \"8:[ProgramFilesFolder][Manufacturer]\\\\[ProductName]\"\n            \"Name\" = \"8:#1925\"\n            \"AlwaysCreate\" = \"11:FALSE\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Property\" = \"8:TARGETDIR\"\n                \"Folders\"\n                {\n                }\n            }\n        }\n        \"LaunchCondition\"\n        {\n        }\n        \"Locator\"\n        {\n        }\n        \"MsiBootstrapper\"\n        {\n        \"LangId\" = \"3:1033\"\n        \"RequiresElevation\" = \"11:FALSE\"\n        }\n        \"Product\"\n        {\n        \"Name\" = \"8:Microsoft Visual Studio\"\n        \"ProductName\" = \"8:FFmpeg Player\"\n        \"ProductCode\" = \"8:{75A04463-09D1-4BE7-A045-58CACA8F9664}\"\n        \"PackageCode\" = \"8:{5FB1158C-B95D-4B33-BC3A-0B88305C2B3B}\"\n        \"UpgradeCode\" = \"8:{0D785376-AABE-42D5-B21F-916C345075C2}\"\n        \"AspNetVersion\" = \"8:4.0.30319.0\"\n        \"RestartWWWService\" = \"11:FALSE\"\n        \"RemovePreviousVersions\" = \"11:FALSE\"\n        \"DetectNewerInstalledVersion\" = \"11:TRUE\"\n        \"InstallAllUsers\" = \"11:FALSE\"\n        \"ProductVersion\" = \"8:0.1.60\"\n        \"Manufacturer\" = \"8:aliakseis\"\n        \"ARPHELPTELEPHONE\" = \"8:\"\n        \"ARPHELPLINK\" = \"8:\"\n        \"Title\" = \"8:FFmpeg Player Setup\"\n        \"Subject\" = \"8:\"\n        \"ARPCONTACT\" = \"8:aliakseis\"\n        \"Keywords\" = \"8:\"\n        \"ARPCOMMENTS\" = \"8:\"\n        \"ARPURLINFOABOUT\" = \"8:\"\n        \"ARPPRODUCTICON\" = \"8:\"\n        \"ARPIconIndex\" = \"3:0\"\n        \"SearchPath\" = \"8:\"\n        \"UseSystemSearchPath\" = \"11:TRUE\"\n        \"TargetPlatform\" = \"3:0\"\n        \"PreBuildEvent\" = \"8:\"\n        \"PostBuildEvent\" = \"8:\"\n        \"RunPostBuildEvent\" = \"3:0\"\n        }\n        \"Registry\"\n        {\n            \"HKLM\"\n            {\n                \"Keys\"\n                {\n                    \"{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_8B53D0A75414407DAC4C298784EF3141\"\n                    {\n                    \"Name\" = \"8:Software\"\n                    \"Condition\" = \"8:\"\n                    \"AlwaysCreate\" = \"11:FALSE\"\n                    \"DeleteAtUninstall\" = \"11:FALSE\"\n                    \"Transitive\" = \"11:FALSE\"\n                        \"Keys\"\n                        {\n                            \"{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_D5C8CECBFFAF422CA3F468589A3F86F1\"\n                            {\n                            \"Name\" = \"8:[Manufacturer]\"\n                            \"Condition\" = \"8:\"\n                            \"AlwaysCreate\" = \"11:FALSE\"\n                            \"DeleteAtUninstall\" = \"11:FALSE\"\n                            \"Transitive\" = \"11:FALSE\"\n                                \"Keys\"\n                                {\n                                }\n                                \"Values\"\n                                {\n                                }\n                            }\n                        }\n                        \"Values\"\n                        {\n                        }\n                    }\n                }\n            }\n            \"HKCU\"\n            {\n                \"Keys\"\n                {\n                    \"{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_CE9477C0C34D4D29B75118BAE38E083D\"\n                    {\n                    \"Name\" = \"8:Software\"\n                    \"Condition\" = \"8:\"\n                    \"AlwaysCreate\" = \"11:FALSE\"\n                    \"DeleteAtUninstall\" = \"11:FALSE\"\n                    \"Transitive\" = \"11:FALSE\"\n                        \"Keys\"\n                        {\n                            \"{60EA8692-D2D5-43EB-80DC-7906BF13D6EF}:_5AD054C81E184E23B61586D130BF43E2\"\n                            {\n                            \"Name\" = \"8:[Manufacturer]\"\n                            \"Condition\" = \"8:\"\n                            \"AlwaysCreate\" = \"11:FALSE\"\n                            \"DeleteAtUninstall\" = \"11:FALSE\"\n                            \"Transitive\" = \"11:FALSE\"\n                                \"Keys\"\n                                {\n                                }\n                                \"Values\"\n                                {\n                                }\n                            }\n                        }\n                        \"Values\"\n                        {\n                        }\n                    }\n                }\n            }\n            \"HKCR\"\n            {\n                \"Keys\"\n                {\n                }\n            }\n            \"HKU\"\n            {\n                \"Keys\"\n                {\n                }\n            }\n            \"HKPU\"\n            {\n                \"Keys\"\n                {\n                }\n            }\n        }\n        \"Sequences\"\n        {\n        }\n        \"Shortcut\"\n        {\n            \"{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_0279D2BC938B460AB0B3840652A35B5E\"\n            {\n            \"Name\" = \"8:Remove pytube\"\n            \"Arguments\" = \"8:\"\n            \"Description\" = \"8:\"\n            \"ShowCmd\" = \"3:7\"\n            \"IconIndex\" = \"3:0\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Target\" = \"8:_A4B43CDF9CA54C19AF7D23DB37A100AC\"\n            \"Folder\" = \"8:_9B328E46D8A9465692C2C0A26ECD0EB4\"\n            \"WorkingFolder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Icon\" = \"8:\"\n            \"Feature\" = \"8:\"\n            }\n            \"{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_029CAA7D4EB448C98C4D939B2F49B1AE\"\n            {\n            \"Name\" = \"8:FFmpeg Player\"\n            \"Arguments\" = \"8:\"\n            \"Description\" = \"8:\"\n            \"ShowCmd\" = \"3:1\"\n            \"IconIndex\" = \"3:0\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Target\" = \"8:_FA750DBCBC084FE991EDD407C9629097\"\n            \"Folder\" = \"8:_9B328E46D8A9465692C2C0A26ECD0EB4\"\n            \"WorkingFolder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Icon\" = \"8:_7BBE6F8C77DD46679E86F836865E5268\"\n            \"Feature\" = \"8:\"\n            }\n            \"{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_39657F46CF514780A9D5D8B756C09F30\"\n            {\n            \"Name\" = \"8:Remove youtube_transcript_api\"\n            \"Arguments\" = \"8:\"\n            \"Description\" = \"8:\"\n            \"ShowCmd\" = \"3:7\"\n            \"IconIndex\" = \"3:0\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Target\" = \"8:_432363CD76D0480AA7084E8FF9F2BE71\"\n            \"Folder\" = \"8:_9B328E46D8A9465692C2C0A26ECD0EB4\"\n            \"WorkingFolder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Icon\" = \"8:\"\n            \"Feature\" = \"8:\"\n            }\n            \"{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_7927A90BD084447D927AF769176382C4\"\n            {\n            \"Name\" = \"8:Modify git_subst.cfg\"\n            \"Arguments\" = \"8:\"\n            \"Description\" = \"8:\"\n            \"ShowCmd\" = \"3:7\"\n            \"IconIndex\" = \"3:0\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Target\" = \"8:_1BB4844D47E14A15B89CF19C542161BB\"\n            \"Folder\" = \"8:_9B328E46D8A9465692C2C0A26ECD0EB4\"\n            \"WorkingFolder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Icon\" = \"8:\"\n            \"Feature\" = \"8:\"\n            }\n            \"{970C0BB2-C7D0-45D7-ABFA-7EC378858BC0}:_868418E8894F4D2F9641A497BCEE6D47\"\n            {\n            \"Name\" = \"8:FFmpeg Player\"\n            \"Arguments\" = \"8:\"\n            \"Description\" = \"8:\"\n            \"ShowCmd\" = \"3:1\"\n            \"IconIndex\" = \"3:0\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Target\" = \"8:_FA750DBCBC084FE991EDD407C9629097\"\n            \"Folder\" = \"8:_164318547FB24CA28F6F77C529476D36\"\n            \"WorkingFolder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Icon\" = \"8:_7BBE6F8C77DD46679E86F836865E5268\"\n            \"Feature\" = \"8:\"\n            }\n        }\n        \"UserInterface\"\n        {\n            \"{DF760B10-853B-4699-99F2-AFF7185B4A62}:_393FF30E69B34CD8BD878D4DD6D8EFA3\"\n            {\n            \"Name\" = \"8:#1901\"\n            \"Sequence\" = \"3:1\"\n            \"Attributes\" = \"3:2\"\n                \"Dialogs\"\n                {\n                    \"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_043AA40592BF4398847515376E58417A\"\n                    {\n                    \"Sequence\" = \"3:100\"\n                    \"DisplayName\" = \"8:Progress\"\n                    \"UseDynamicProperties\" = \"11:TRUE\"\n                    \"IsDependency\" = \"11:FALSE\"\n                    \"SourcePath\" = \"8:<VsdDialogDir>\\\\VsdProgressDlg.wid\"\n                        \"Properties\"\n                        {\n                            \"BannerBitmap\"\n                            {\n                            \"Name\" = \"8:BannerBitmap\"\n                            \"DisplayName\" = \"8:#1001\"\n                            \"Description\" = \"8:#1101\"\n                            \"Type\" = \"3:8\"\n                            \"ContextData\" = \"8:Bitmap\"\n                            \"Attributes\" = \"3:4\"\n                            \"Setting\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                            \"ShowProgress\"\n                            {\n                            \"Name\" = \"8:ShowProgress\"\n                            \"DisplayName\" = \"8:#1009\"\n                            \"Description\" = \"8:#1109\"\n                            \"Type\" = \"3:5\"\n                            \"ContextData\" = \"8:1;True=1;False=0\"\n                            \"Attributes\" = \"3:0\"\n                            \"Setting\" = \"3:0\"\n                            \"Value\" = \"3:1\"\n                            \"DefaultValue\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                        }\n                    }\n                }\n            }\n            \"{DF760B10-853B-4699-99F2-AFF7185B4A62}:_5A4E5B83027E4E98829E4F6C0062EFE4\"\n            {\n            \"Name\" = \"8:#1902\"\n            \"Sequence\" = \"3:2\"\n            \"Attributes\" = \"3:3\"\n                \"Dialogs\"\n                {\n                    \"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_2D89A43D8D1D46D2A91B0B0A5680B5FE\"\n                    {\n                    \"Sequence\" = \"3:100\"\n                    \"DisplayName\" = \"8:Finished\"\n                    \"UseDynamicProperties\" = \"11:TRUE\"\n                    \"IsDependency\" = \"11:FALSE\"\n                    \"SourcePath\" = \"8:<VsdDialogDir>\\\\VsdAdminFinishedDlg.wid\"\n                        \"Properties\"\n                        {\n                            \"BannerBitmap\"\n                            {\n                            \"Name\" = \"8:BannerBitmap\"\n                            \"DisplayName\" = \"8:#1001\"\n                            \"Description\" = \"8:#1101\"\n                            \"Type\" = \"3:8\"\n                            \"ContextData\" = \"8:Bitmap\"\n                            \"Attributes\" = \"3:4\"\n                            \"Setting\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                        }\n                    }\n                }\n            }\n            \"{DF760B10-853B-4699-99F2-AFF7185B4A62}:_7772B3E764094DD0AB14C513B0CA0143\"\n            {\n            \"Name\" = \"8:#1901\"\n            \"Sequence\" = \"3:2\"\n            \"Attributes\" = \"3:2\"\n                \"Dialogs\"\n                {\n                    \"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_E267556BF8874F83A64C71B33B0D327A\"\n                    {\n                    \"Sequence\" = \"3:100\"\n                    \"DisplayName\" = \"8:Progress\"\n                    \"UseDynamicProperties\" = \"11:TRUE\"\n                    \"IsDependency\" = \"11:FALSE\"\n                    \"SourcePath\" = \"8:<VsdDialogDir>\\\\VsdAdminProgressDlg.wid\"\n                        \"Properties\"\n                        {\n                            \"BannerBitmap\"\n                            {\n                            \"Name\" = \"8:BannerBitmap\"\n                            \"DisplayName\" = \"8:#1001\"\n                            \"Description\" = \"8:#1101\"\n                            \"Type\" = \"3:8\"\n                            \"ContextData\" = \"8:Bitmap\"\n                            \"Attributes\" = \"3:4\"\n                            \"Setting\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                            \"ShowProgress\"\n                            {\n                            \"Name\" = \"8:ShowProgress\"\n                            \"DisplayName\" = \"8:#1009\"\n                            \"Description\" = \"8:#1109\"\n                            \"Type\" = \"3:5\"\n                            \"ContextData\" = \"8:1;True=1;False=0\"\n                            \"Attributes\" = \"3:0\"\n                            \"Setting\" = \"3:0\"\n                            \"Value\" = \"3:1\"\n                            \"DefaultValue\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                        }\n                    }\n                }\n            }\n            \"{DF760B10-853B-4699-99F2-AFF7185B4A62}:_95F2869C2D0E48FB970C95D59E7A999E\"\n            {\n            \"Name\" = \"8:#1902\"\n            \"Sequence\" = \"3:1\"\n            \"Attributes\" = \"3:3\"\n                \"Dialogs\"\n                {\n                    \"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_8144A416E6DD44D59FCA783CDD83C11A\"\n                    {\n                    \"Sequence\" = \"3:100\"\n                    \"DisplayName\" = \"8:Finished\"\n                    \"UseDynamicProperties\" = \"11:TRUE\"\n                    \"IsDependency\" = \"11:FALSE\"\n                    \"SourcePath\" = \"8:<VsdDialogDir>\\\\VsdFinishedDlg.wid\"\n                        \"Properties\"\n                        {\n                            \"BannerBitmap\"\n                            {\n                            \"Name\" = \"8:BannerBitmap\"\n                            \"DisplayName\" = \"8:#1001\"\n                            \"Description\" = \"8:#1101\"\n                            \"Type\" = \"3:8\"\n                            \"ContextData\" = \"8:Bitmap\"\n                            \"Attributes\" = \"3:4\"\n                            \"Setting\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                            \"UpdateText\"\n                            {\n                            \"Name\" = \"8:UpdateText\"\n                            \"DisplayName\" = \"8:#1058\"\n                            \"Description\" = \"8:#1158\"\n                            \"Type\" = \"3:15\"\n                            \"ContextData\" = \"8:\"\n                            \"Attributes\" = \"3:0\"\n                            \"Setting\" = \"3:1\"\n                            \"Value\" = \"8:#1258\"\n                            \"DefaultValue\" = \"8:#1258\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                        }\n                    }\n                }\n            }\n            \"{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_A5AA2C6D0AF24A8692A8DBC2C610F558\"\n            {\n            \"UseDynamicProperties\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"SourcePath\" = \"8:<VsdDialogDir>\\\\VsdUserInterface.wim\"\n            }\n            \"{DF760B10-853B-4699-99F2-AFF7185B4A62}:_C50ADF40726F4E1FBEA40BC383EC61E2\"\n            {\n            \"Name\" = \"8:#1900\"\n            \"Sequence\" = \"3:2\"\n            \"Attributes\" = \"3:1\"\n                \"Dialogs\"\n                {\n                    \"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_2A72F1DAA40242A7B1401E58C2E2FD05\"\n                    {\n                    \"Sequence\" = \"3:300\"\n                    \"DisplayName\" = \"8:Confirm Installation\"\n                    \"UseDynamicProperties\" = \"11:TRUE\"\n                    \"IsDependency\" = \"11:FALSE\"\n                    \"SourcePath\" = \"8:<VsdDialogDir>\\\\VsdAdminConfirmDlg.wid\"\n                        \"Properties\"\n                        {\n                            \"BannerBitmap\"\n                            {\n                            \"Name\" = \"8:BannerBitmap\"\n                            \"DisplayName\" = \"8:#1001\"\n                            \"Description\" = \"8:#1101\"\n                            \"Type\" = \"3:8\"\n                            \"ContextData\" = \"8:Bitmap\"\n                            \"Attributes\" = \"3:4\"\n                            \"Setting\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                        }\n                    }\n                    \"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_5E783BE669C84563892F59A2111A831F\"\n                    {\n                    \"Sequence\" = \"3:100\"\n                    \"DisplayName\" = \"8:Welcome\"\n                    \"UseDynamicProperties\" = \"11:TRUE\"\n                    \"IsDependency\" = \"11:FALSE\"\n                    \"SourcePath\" = \"8:<VsdDialogDir>\\\\VsdAdminWelcomeDlg.wid\"\n                        \"Properties\"\n                        {\n                            \"BannerBitmap\"\n                            {\n                            \"Name\" = \"8:BannerBitmap\"\n                            \"DisplayName\" = \"8:#1001\"\n                            \"Description\" = \"8:#1101\"\n                            \"Type\" = \"3:8\"\n                            \"ContextData\" = \"8:Bitmap\"\n                            \"Attributes\" = \"3:4\"\n                            \"Setting\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                            \"CopyrightWarning\"\n                            {\n                            \"Name\" = \"8:CopyrightWarning\"\n                            \"DisplayName\" = \"8:#1002\"\n                            \"Description\" = \"8:#1102\"\n                            \"Type\" = \"3:3\"\n                            \"ContextData\" = \"8:\"\n                            \"Attributes\" = \"3:0\"\n                            \"Setting\" = \"3:2\"\n                            \"Value\" = \"8:\"\n                            \"DefaultValue\" = \"8:#1202\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                            \"Welcome\"\n                            {\n                            \"Name\" = \"8:Welcome\"\n                            \"DisplayName\" = \"8:#1003\"\n                            \"Description\" = \"8:#1103\"\n                            \"Type\" = \"3:3\"\n                            \"ContextData\" = \"8:\"\n                            \"Attributes\" = \"3:0\"\n                            \"Setting\" = \"3:1\"\n                            \"Value\" = \"8:#1203\"\n                            \"DefaultValue\" = \"8:#1203\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                        }\n                    }\n                    \"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_B113448BB15A4F0A973E12015C5F0960\"\n                    {\n                    \"Sequence\" = \"3:200\"\n                    \"DisplayName\" = \"8:Installation Folder\"\n                    \"UseDynamicProperties\" = \"11:TRUE\"\n                    \"IsDependency\" = \"11:FALSE\"\n                    \"SourcePath\" = \"8:<VsdDialogDir>\\\\VsdAdminFolderDlg.wid\"\n                        \"Properties\"\n                        {\n                            \"BannerBitmap\"\n                            {\n                            \"Name\" = \"8:BannerBitmap\"\n                            \"DisplayName\" = \"8:#1001\"\n                            \"Description\" = \"8:#1101\"\n                            \"Type\" = \"3:8\"\n                            \"ContextData\" = \"8:Bitmap\"\n                            \"Attributes\" = \"3:4\"\n                            \"Setting\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                        }\n                    }\n                }\n            }\n            \"{DF760B10-853B-4699-99F2-AFF7185B4A62}:_E7EAECAC199E486B82068B8BFE02B183\"\n            {\n            \"Name\" = \"8:#1900\"\n            \"Sequence\" = \"3:1\"\n            \"Attributes\" = \"3:1\"\n                \"Dialogs\"\n                {\n                    \"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_3A13CD611BCD4060ADF44B3B2BCC21C3\"\n                    {\n                    \"Sequence\" = \"3:300\"\n                    \"DisplayName\" = \"8:Confirm Installation\"\n                    \"UseDynamicProperties\" = \"11:TRUE\"\n                    \"IsDependency\" = \"11:FALSE\"\n                    \"SourcePath\" = \"8:<VsdDialogDir>\\\\VsdConfirmDlg.wid\"\n                        \"Properties\"\n                        {\n                            \"BannerBitmap\"\n                            {\n                            \"Name\" = \"8:BannerBitmap\"\n                            \"DisplayName\" = \"8:#1001\"\n                            \"Description\" = \"8:#1101\"\n                            \"Type\" = \"3:8\"\n                            \"ContextData\" = \"8:Bitmap\"\n                            \"Attributes\" = \"3:4\"\n                            \"Setting\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                        }\n                    }\n                    \"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_A5266A82833A4A9A89F20785556069A0\"\n                    {\n                    \"Sequence\" = \"3:100\"\n                    \"DisplayName\" = \"8:Welcome\"\n                    \"UseDynamicProperties\" = \"11:TRUE\"\n                    \"IsDependency\" = \"11:FALSE\"\n                    \"SourcePath\" = \"8:<VsdDialogDir>\\\\VsdWelcomeDlg.wid\"\n                        \"Properties\"\n                        {\n                            \"BannerBitmap\"\n                            {\n                            \"Name\" = \"8:BannerBitmap\"\n                            \"DisplayName\" = \"8:#1001\"\n                            \"Description\" = \"8:#1101\"\n                            \"Type\" = \"3:8\"\n                            \"ContextData\" = \"8:Bitmap\"\n                            \"Attributes\" = \"3:4\"\n                            \"Setting\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                            \"CopyrightWarning\"\n                            {\n                            \"Name\" = \"8:CopyrightWarning\"\n                            \"DisplayName\" = \"8:#1002\"\n                            \"Description\" = \"8:#1102\"\n                            \"Type\" = \"3:3\"\n                            \"ContextData\" = \"8:\"\n                            \"Attributes\" = \"3:0\"\n                            \"Setting\" = \"3:2\"\n                            \"Value\" = \"8:\"\n                            \"DefaultValue\" = \"8:#1202\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                            \"Welcome\"\n                            {\n                            \"Name\" = \"8:Welcome\"\n                            \"DisplayName\" = \"8:#1003\"\n                            \"Description\" = \"8:#1103\"\n                            \"Type\" = \"3:3\"\n                            \"ContextData\" = \"8:\"\n                            \"Attributes\" = \"3:0\"\n                            \"Setting\" = \"3:1\"\n                            \"Value\" = \"8:#1203\"\n                            \"DefaultValue\" = \"8:#1203\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                        }\n                    }\n                    \"{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_BAFBB03D526A404DA170E80641D3DAE0\"\n                    {\n                    \"Sequence\" = \"3:200\"\n                    \"DisplayName\" = \"8:Installation Folder\"\n                    \"UseDynamicProperties\" = \"11:TRUE\"\n                    \"IsDependency\" = \"11:FALSE\"\n                    \"SourcePath\" = \"8:<VsdDialogDir>\\\\VsdFolderDlg.wid\"\n                        \"Properties\"\n                        {\n                            \"BannerBitmap\"\n                            {\n                            \"Name\" = \"8:BannerBitmap\"\n                            \"DisplayName\" = \"8:#1001\"\n                            \"Description\" = \"8:#1101\"\n                            \"Type\" = \"3:8\"\n                            \"ContextData\" = \"8:Bitmap\"\n                            \"Attributes\" = \"3:4\"\n                            \"Setting\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                            \"InstallAllUsersVisible\"\n                            {\n                            \"Name\" = \"8:InstallAllUsersVisible\"\n                            \"DisplayName\" = \"8:#1059\"\n                            \"Description\" = \"8:#1159\"\n                            \"Type\" = \"3:5\"\n                            \"ContextData\" = \"8:1;True=1;False=0\"\n                            \"Attributes\" = \"3:0\"\n                            \"Setting\" = \"3:0\"\n                            \"Value\" = \"3:1\"\n                            \"DefaultValue\" = \"3:1\"\n                            \"UsePlugInResources\" = \"11:TRUE\"\n                            }\n                        }\n                    }\n                }\n            }\n            \"{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_FEDCE1090B054055A6CB8FE90EB522D6\"\n            {\n            \"UseDynamicProperties\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"SourcePath\" = \"8:<VsdDialogDir>\\\\VsdBasicDialogs.wim\"\n            }\n        }\n        \"MergeModule\"\n        {\n            \"{CEE29DC0-9FBA-4B99-8D47-5BC643D9B626}:_4E1B2E066177453BAA56F6A639DA8C91\"\n            {\n            \"UseDynamicProperties\" = \"11:TRUE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"SourcePath\" = \"8:C:\\\\Program Files (x86)\\\\Microsoft Visual Studio\\\\2017\\\\Community\\\\VC\\\\Redist\\\\MSVC\\\\14.16.27012\\\\MergeModules\\\\Microsoft_VC141_MFC_x86.msm\"\n                \"Properties\"\n                {\n                }\n            \"LanguageId\" = \"3:0\"\n            \"Exclude\" = \"11:FALSE\"\n            \"Folder\" = \"8:\"\n            \"Feature\" = \"8:\"\n            \"IsolateTo\" = \"8:\"\n            }\n            \"{CEE29DC0-9FBA-4B99-8D47-5BC643D9B626}:_E36BE16F84CF4B1F8F13230F495EB066\"\n            {\n            \"UseDynamicProperties\" = \"11:TRUE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"SourcePath\" = \"8:C:\\\\Program Files (x86)\\\\Microsoft Visual Studio\\\\2017\\\\Community\\\\VC\\\\Redist\\\\MSVC\\\\14.16.27012\\\\MergeModules\\\\Microsoft_VC141_CRT_x86.msm\"\n                \"Properties\"\n                {\n                }\n            \"LanguageId\" = \"3:0\"\n            \"Exclude\" = \"11:FALSE\"\n            \"Folder\" = \"8:\"\n            \"Feature\" = \"8:\"\n            \"IsolateTo\" = \"8:\"\n            }\n        }\n        \"ProjectOutput\"\n        {\n            \"{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_02EFEE03BFE64741B0ABE34B02FC32B5\"\n            {\n            \"SourcePath\" = \"8:..\\\\Release\\\\HttpDownload.exe\"\n            \"TargetName\" = \"8:\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            \"ProjectOutputGroupRegister\" = \"3:1\"\n            \"OutputConfiguration\" = \"8:\"\n            \"OutputGroupCanonicalName\" = \"8:Built\"\n            \"OutputProjectGuid\" = \"8:{A4113679-4736-494B-B8D2-3C35B34E5491}\"\n            \"ShowKeyOutput\" = \"11:TRUE\"\n                \"ExcludeFilters\"\n                {\n                }\n            }\n            \"{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_13D05759FE0A4D95A0231F4083F018C4\"\n            {\n            \"SourcePath\" = \"8:..\\\\Release\\\\ToUTF8.exe\"\n            \"TargetName\" = \"8:\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            \"ProjectOutputGroupRegister\" = \"3:1\"\n            \"OutputConfiguration\" = \"8:\"\n            \"OutputGroupCanonicalName\" = \"8:Built\"\n            \"OutputProjectGuid\" = \"8:{F082EF32-A1D0-48B9-9AF1-DC56178EDE92}\"\n            \"ShowKeyOutput\" = \"11:TRUE\"\n                \"ExcludeFilters\"\n                {\n                }\n            }\n            \"{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_C9AF4EE415C543558DFD791707994B89\"\n            {\n            \"SourcePath\" = \"8:\"\n            \"TargetName\" = \"8:\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            \"ProjectOutputGroupRegister\" = \"3:1\"\n            \"OutputConfiguration\" = \"8:\"\n            \"OutputGroupCanonicalName\" = \"8:ContentFiles\"\n            \"OutputProjectGuid\" = \"8:{BC1BC9F1-893D-4715-818A-F37F74EB5710}\"\n            \"ShowKeyOutput\" = \"11:TRUE\"\n                \"ExcludeFilters\"\n                {\n                }\n            }\n            \"{5259A561-127C-4D43-A0A1-72F10C7B3BF8}:_FA750DBCBC084FE991EDD407C9629097\"\n            {\n            \"SourcePath\" = \"8:..\\\\Release\\\\Player.exe\"\n            \"TargetName\" = \"8:\"\n            \"Tag\" = \"8:\"\n            \"Folder\" = \"8:_B8C7CD6341EA4A8BAFE1F90F54D378CA\"\n            \"Condition\" = \"8:\"\n            \"Transitive\" = \"11:FALSE\"\n            \"Vital\" = \"11:TRUE\"\n            \"ReadOnly\" = \"11:FALSE\"\n            \"Hidden\" = \"11:FALSE\"\n            \"System\" = \"11:FALSE\"\n            \"Permanent\" = \"11:FALSE\"\n            \"SharedLegacy\" = \"11:FALSE\"\n            \"PackageAs\" = \"3:1\"\n            \"Register\" = \"3:1\"\n            \"Exclude\" = \"11:FALSE\"\n            \"IsDependency\" = \"11:FALSE\"\n            \"IsolateTo\" = \"8:\"\n            \"ProjectOutputGroupRegister\" = \"3:1\"\n            \"OutputConfiguration\" = \"8:\"\n            \"OutputGroupCanonicalName\" = \"8:Built\"\n            \"OutputProjectGuid\" = \"8:{C90196CD-7354-4ED4-BFC0-E51A7E1CBE3C}\"\n            \"ShowKeyOutput\" = \"11:TRUE\"\n                \"ExcludeFilters\"\n                {\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "ThirdParty/include/cmdline/cmdline.hpp",
    "content": "/*\n  Copyright (c) 2009, Hideyuki Tanaka\n  All rights reserved.\n\n  Redistribution and use in source and binary forms, with or without\n  modification, are permitted provided that the following conditions are met:\n  * Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n  * Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in the\n  documentation and/or other materials provided with the distribution.\n  * Neither the name of the <organization> nor the\n  names of its contributors may be used to endorse or promote products\n  derived from this software without specific prior written permission.\n\n  THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY\n  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n  DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY\n  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n*/\n\n#pragma once\n\n#include <iostream>\n#include <iterator>\n#include <sstream>\n#include <vector>\n#include <unordered_map>\n#include <string>\n#include <stdexcept>\n#include <algorithm>\n#include <initializer_list>\n#include <memory>\n#include <cstring>\n\nnamespace cmdline\n{\n    namespace detail\n    {\n\n        template <typename Target, typename Source>\n        struct lexical_cast_t\n        {\n            static Target cast(const Source &arg)\n            {\n                return static_cast<Target>(arg);\n            }\n        };\n\n        template <typename Source>\n        struct lexical_cast_t<std::string, Source>\n        {\n            static std::string cast(const Source &arg)\n            {\n                return std::to_string(arg);\n            }\n        };\n\n        template <typename Target>\n        struct lexical_cast_t<Target, std::string>\n        {\n            static Target cast(const std::string &arg)\n            {\n                static std::istringstream iss;\n                Target ret{};\n                iss.str(arg);\n                iss >> ret;\n                iss.clear();\n                return ret;\n            }\n        };\n\n        template <typename Target, typename Source, std::enable_if_t<!std::is_same<Target, Source>::value> * = nullptr>\n        Target lexical_cast(const Source &arg)\n        {\n            return lexical_cast_t<Target, Source>::cast(arg);\n        }\n\n        template <typename Target, typename Source, std::enable_if_t<std::is_same<Target, Source>::value> * = nullptr>\n        Target lexical_cast(const Source &arg)\n        {\n            return arg;\n        }\n\n        template <typename T, std::enable_if_t<std::is_integral<T>::value> * = nullptr>\n        std::string readable_typename()\n        {\n            return \"Integer\";\n        }\n\n        template <typename T, std::enable_if_t<std::is_floating_point<T>::value> * = nullptr>\n        std::string readable_typename()\n        {\n            return \"Floating-point\";\n        }\n\n        template <typename T, std::enable_if_t<std::is_same<T, std::string>::value> * = nullptr>\n        std::string readable_typename()\n        {\n            return \"String\";\n        }\n\n        template <typename T>\n        std::string default_value(T def)\n        {\n            return detail::lexical_cast<std::string>(def);\n        }\n\n    } // detail\n\n    //-----\n    template <class T>\n    struct default_reader\n    {\n        T operator()(const std::string &str)\n        {\n            return detail::lexical_cast<T>(str);\n        }\n    };\n\n    template <class T>\n    struct range_reader\n    {\n        range_reader(const T &low, const T &high) : low(low), high(high) {}\n        T operator()(const std::string &s) const\n        {\n            T ret = default_reader<T>()(s);\n            if (!(ret >= low && ret <= high))\n                throw std::exception();\n            return ret;\n        }\n\n    private:\n        T low, high;\n    };\n\n    template <class T>\n    range_reader<T> range(const T &low, const T &high)\n    {\n        return range_reader<T>(low, high);\n    }\n\n    template <class T>\n    struct oneof_reader\n    {\n        oneof_reader(std::initializer_list<T> list) : alt(list) {}\n\n        T operator()(const std::string &s)\n        {\n            T ret = default_reader<T>()(s);\n            if (std::find(alt.begin(), alt.end(), ret) == alt.end())\n                throw std::exception();\n            return ret;\n        }\n\n    private:\n        std::vector<T> alt;\n    };\n\n    template <class T, class... Args>\n    oneof_reader<T> oneof(T a1, Args... args)\n    {\n        return oneof_reader<T>{a1, args...};\n    }\n\n    template <class Target, class Checker>\n    auto custom_reader(Checker &&checker)\n    {\n        return [checker](const std::string &s) -> Target\n        {\n            Target ret = default_reader<Target>()(s);\n            if (!checker(ret))\n                throw std::exception();\n            return ret;\n        };\n    }\n    //-----\n\n    class parser\n    {\n    public:\n        void add(const std::string &name,\n                 char short_name = 0,\n                 const std::string &desc = std::string{})\n        {\n            if (options.find(name) != options.end())\n            {\n                std::cerr << \"multiple definition: \" + name << '\\n';\n                std::exit(1);\n            }\n            options.emplace(name, std::make_shared<option_without_value>(name, short_name, desc));\n            ordered.emplace_back(options[name]);\n        }\n\n        template <class T, class F = default_reader<T>>\n        void add(const std::string &name,\n                 char short_name = 0,\n                 const std::string &desc = std::string{},\n                 bool need = true,\n                 const T def = T(),\n                 F reader = F())\n        {\n            if (options.find(name) != options.end())\n            {\n                std::cerr << \"multiple definition: \" + name << '\\n';\n                std::exit(1);\n            }\n            options.emplace(name, std::make_shared<option_with_value_with_reader<T, F>>(name, short_name, need, def, desc, reader));\n            ordered.emplace_back(options[name]);\n        }\n\n        void footer(const std::string &f)\n        {\n            ftr = f;\n        }\n\n        void set_program_name(const std::string &name)\n        {\n            prog_name = name;\n        }\n\n        bool exist(const std::string &name) const\n        {\n            if (options.find(name) == options.end())\n            {\n                std::cerr << \"there is no flag: --\" + name << '\\n'\n                          << usage();\n                std::exit(1);\n            }\n            return options.find(name)->second->has_set();\n        }\n\n        template <class T>\n        const T &get(const std::string &name) const\n        {\n            if (options.find(name) == options.end())\n            {\n                std::cerr << \"there is no flag: --\" + name << '\\n'\n                          << usage();\n                std::exit(1);\n            }\n            auto p = std::dynamic_pointer_cast<const option_with_value<T>>(options.find(name)->second);\n            if (p == nullptr)\n            {\n                std::cerr << \"type mismatch flag '\" + name + \"'\" << '\\n'\n                          << usage();\n                std::exit(1);\n            }\n            return p->get();\n        }\n\n        const std::vector<std::string> &rest() const\n        {\n            return others;\n        }\n\n        bool parse(const std::string &arg)\n        {\n            std::vector<std::string> args;\n\n            std::string buf;\n            bool in_quote = false;\n            for (std::size_t i = 0; i < arg.length(); i++)\n            {\n                if (arg[i] == '\\\"')\n                {\n                    in_quote = !in_quote;\n                    continue;\n                }\n\n                if (arg[i] == ' ' && !in_quote)\n                {\n                    args.emplace_back(buf);\n                    buf = \"\";\n                    continue;\n                }\n\n                if (arg[i] == '\\\\')\n                {\n                    i++;\n                    if (i >= arg.length())\n                    {\n                        errors.emplace_back(\"unexpected occurrence of '\\\\' at end of string\");\n                        return false;\n                    }\n                }\n\n                buf += arg[i];\n            }\n\n            if (in_quote)\n            {\n                errors.emplace_back(\"quote is not closed\");\n                return false;\n            }\n\n            if (buf.length() > 0)\n                args.emplace_back(buf);\n\n            for (std::size_t i = 0; i < args.size(); i++)\n                std::cout << \"\\\"\" << args[i] << \"\\\"\" << std::endl;\n\n            return parse(args);\n        }\n\n        bool parse(const std::vector<std::string> &args)\n        {\n            int argc = static_cast<int>(args.size());\n            std::vector<const char *> argv(argc);\n\n            for (int i = 0; i < argc; i++)\n                argv[i] = args[i].c_str();\n\n            return parse(argc, &argv[0]);\n        }\n\n        bool parse(int argc, const char *const argv[])\n        {\n            errors.clear();\n            others.clear();\n\n            if (argc < 1)\n            {\n                errors.emplace_back(\"argument number must be longer than 0\");\n                return false;\n            }\n            if (prog_name.empty())\n                prog_name = argv[0];\n\n            std::unordered_map<char, std::string> lookup;\n            for (auto p = options.begin(); p != options.end(); p++)\n            {\n                if (p->first.length() == 0)\n                    continue;\n                char initial = p->second->short_name();\n                if (initial)\n                {\n                    if (lookup.find(initial) != lookup.end())\n                    {\n                        lookup[initial].clear();\n                        errors.emplace_back(std::string(\"short option '\") + initial + \"' is ambiguous\");\n                        return false;\n                    }\n                    else\n                        lookup[initial] = p->first;\n                }\n            }\n\n            for (int i = 1; i < argc; i++)\n            {\n                if (std::strncmp(argv[i], \"--\", 2) == 0)\n                {\n                    const char *p = std::strchr(argv[i] + 2, '=');\n                    if (p)\n                    {\n                        set_option(std::string{argv[i] + 2, p}, std::string{p + 1});\n                    }\n                    else\n                    {\n                        std::string name(argv[i] + 2);\n                        if (options.find(name) == options.end())\n                        {\n                            errors.emplace_back(\"undefined option: --\" + name);\n                        }\n                        else if (options[name]->has_value())\n                        {\n                            if (i + 1 >= argc)\n                            {\n                                errors.emplace_back(\"option needs value: --\" + name);\n                            }\n                            else\n                            {\n                                set_option(name, argv[++i]);\n                            }\n                        }\n                        else\n                        {\n                            set_option(name);\n                        }\n                    }\n                }\n                else if (std::strncmp(argv[i], \"-\", 1) == 0)\n                {\n                    for (int j = 1; argv[i][j]; j++)\n                    {\n                        if (lookup.find(argv[i][j]) == lookup.end())\n                        {\n                            errors.emplace_back(std::string(\"undefined short option: -\") + argv[i][j]);\n                        }\n                        else\n                        {\n                            std::string name = lookup[argv[i][j]];\n                            if (!argv[i][j + 1] && i + 1 < argc && options[name]->has_value())\n                            {\n                                set_option(name, argv[++i]);\n                                break;\n                            }\n                            else\n                            {\n                                set_option(name);\n                            }\n                        }\n                    }\n                }\n                else\n                {\n                    others.emplace_back(argv[i]);\n                }\n            }\n\n            if (errors.empty())\n            {\n                for (auto p = options.begin(); p != options.end(); p++)\n                    if (!p->second->valid())\n                        errors.emplace_back(\"need option: --\" + p->first);\n                return errors.empty();\n            }\n\n            return false;\n        }\n\n        void parse_check(const std::string &arg)\n        {\n            if (options.find(\"help\") == options.end())\n                add(\"help\", '?', \"print this message\");\n            check(parse(arg));\n        }\n\n        void parse_check(const std::vector<std::string> &args)\n        {\n            if (options.find(\"help\") == options.end())\n                add(\"help\", '?', \"print this message\");\n            check(parse(args));\n        }\n\n        void parse_check(int argc, char *argv[])\n        {\n            if (options.find(\"help\") == options.end())\n                add(\"help\", '?', \"print this message\");\n            check(parse(argc, argv));\n        }\n\n        std::string error() const\n        {\n            std::ostringstream os;\n            auto b = std::begin(errors), e = std::end(errors);\n\n            if (b != e)\n            {\n                std::copy(b, std::prev(e), std::ostream_iterator<std::string>(os, \"\\n\"));\n                b = std::prev(e);\n            }\n            if (b != e)\n            {\n                os << *b;\n            }\n\n            return os.str();\n        }\n\n        std::string usage() const\n        {\n            std::ostringstream oss;\n            oss << \"usage: \" << prog_name << \" \";\n            for (std::size_t i = 0; i < ordered.size(); i++)\n            {\n                if (ordered[i]->must())\n                    oss << ordered[i]->short_description() << \" \";\n            }\n\n            oss << \"[options] ... \" << ftr << std::endl;\n            oss << \"options:\" << std::endl;\n\n            std::size_t max_width = 0;\n            for (std::size_t i = 0; i < ordered.size(); i++)\n            {\n                max_width = std::max(max_width, ordered[i]->name().length());\n            }\n            for (std::size_t i = 0; i < ordered.size(); i++)\n            {\n                if (ordered[i]->short_name())\n                {\n                    oss << \"  -\" << ordered[i]->short_name() << \", \";\n                }\n                else\n                {\n                    oss << \"      \";\n                }\n\n                oss << \"--\" << ordered[i]->name();\n                for (std::size_t j = ordered[i]->name().length(); j < max_width + 4; j++)\n                    oss << ' ';\n                oss << ordered[i]->description() << std::endl;\n            }\n            return oss.str();\n        }\n\n    private:\n        void check(bool ok)\n        {\n            if (exist(\"help\"))\n            {\n                std::cout << usage() << std::endl;\n                std::exit(0);\n            }\n            if (!ok)\n            {\n                std::cerr << error() << '\\n'\n                          << usage();\n                std::exit(1);\n            }\n        }\n\n        void set_option(const std::string &name)\n        {\n            if (options.find(name) == options.end())\n            {\n                errors.emplace_back(\"undefined option: --\" + name);\n                return;\n            }\n            if (!options[name]->set())\n            {\n                errors.emplace_back(\"option needs value: --\" + name);\n                return;\n            }\n        }\n\n        void set_option(const std::string &name, const std::string &value)\n        {\n            if (options.find(name) == options.end())\n            {\n                errors.emplace_back(\"undefined option: --\" + name);\n                return;\n            }\n            if (!options[name]->set(value))\n            {\n                errors.emplace_back(\"option value is invalid: --\" + name + \"=\" + value);\n                return;\n            }\n        }\n\n        class option_base\n        {\n        public:\n            virtual ~option_base() {}\n\n            virtual bool has_value() const = 0;\n            virtual bool set() = 0;\n            virtual bool set(const std::string &value) = 0;\n            virtual bool has_set() const = 0;\n            virtual bool valid() const = 0;\n            virtual bool must() const = 0;\n\n            virtual const std::string &name() const = 0;\n            virtual char short_name() const = 0;\n            virtual const std::string &description() const = 0;\n            virtual std::string short_description() const = 0;\n        };\n\n        class option_without_value : public option_base\n        {\n        public:\n            option_without_value(const std::string &name,\n                                 char short_name,\n                                 const std::string &desc)\n                : nam(name), snam(short_name), has(false)\n            {\n                this->desc = format_description(desc);\n            }\n            ~option_without_value() {}\n\n            bool has_value() const { return false; }\n\n            bool set()\n            {\n                has = true;\n                return true;\n            }\n\n            bool set(const std::string &)\n            {\n                return false;\n            }\n\n            bool has_set() const\n            {\n                return has;\n            }\n\n            bool valid() const\n            {\n                return true;\n            }\n\n            bool must() const\n            {\n                return false;\n            }\n\n            const std::string &name() const\n            {\n                return nam;\n            }\n\n            char short_name() const\n            {\n                return snam;\n            }\n\n            const std::string &description() const\n            {\n                return desc;\n            }\n\n            std::string short_description() const\n            {\n                return \"--\" + nam;\n            }\n\n        protected:\n            std::string format_description(const std::string &desc)\n            {\n                std::size_t size = desc.size();\n                std::size_t width = 60;\n                std::string tmp = \"\\n        \";\n                for (std::size_t i = 0; i < size; i += width)\n                    tmp += (desc.substr(i, width > size - i ? size - i : width) + \"\\n        \");\n                return tmp;\n            }\n\n        private:\n            std::string nam;\n            char snam;\n            std::string desc;\n            bool has;\n        };\n\n        template <class T>\n        class option_with_value : public option_base\n        {\n        public:\n            option_with_value(const std::string &name,\n                              char short_name,\n                              bool need,\n                              const T &def,\n                              const std::string &desc)\n                : nam(name), snam(short_name), need(need), has(false), def(def), actual(def)\n            {\n                this->desc = format_description(desc);\n            }\n            ~option_with_value() {}\n\n            const T &get() const\n            {\n                return actual;\n            }\n\n            bool has_value() const { return true; }\n\n            bool set()\n            {\n                return false;\n            }\n\n            bool set(const std::string &value)\n            {\n                try\n                {\n                    actual = read(value);\n                    has = true;\n                }\n                catch (const std::exception)\n                {\n                    return false;\n                }\n                return true;\n            }\n\n            bool has_set() const\n            {\n                return has;\n            }\n\n            bool valid() const\n            {\n                if (need && !has)\n                    return false;\n                return true;\n            }\n\n            bool must() const\n            {\n                return need;\n            }\n\n            const std::string &name() const\n            {\n                return nam;\n            }\n\n            char short_name() const\n            {\n                return snam;\n            }\n\n            const std::string &description() const\n            {\n                return desc;\n            }\n\n            std::string short_description() const\n            {\n                return \"--\" + nam + \"=\" + detail::readable_typename<T>();\n            }\n\n        protected:\n            std::string format_description(const std::string &desc)\n            {\n                std::size_t size = desc.size();\n                std::size_t width = 60;\n                std::string tmp = \"\\n        \";\n                for (std::size_t i = 0; i < size; i += width)\n                    tmp += (desc.substr(i, width > size - i ? size - i : width) + \"\\n        \");\n                return tmp + \" (\" + detail::readable_typename<T>() +\n                       (need ? \"\" : \" [=\" + detail::default_value<T>(def) + \"]\") + \")\\n\";\n            }\n\n            virtual T read(const std::string &s) = 0;\n\n            std::string nam;\n            char snam;\n            bool need;\n            std::string desc;\n\n            bool has;\n            T def;\n            T actual;\n        };\n\n        template <class T, class F>\n        class option_with_value_with_reader : public option_with_value<T>\n        {\n        public:\n            option_with_value_with_reader(const std::string &name,\n                                          char short_name,\n                                          bool need,\n                                          const T def,\n                                          const std::string &desc,\n                                          F reader)\n                : option_with_value<T>(name, short_name, need, def, desc), reader(reader) {}\n\n        private:\n            T read(const std::string &s)\n            {\n                return reader(s);\n            }\n\n            F reader;\n        };\n\n    private:\n        std::unordered_map<std::string, std::shared_ptr<option_base>> options;\n        std::vector<std::shared_ptr<option_base>> ordered;\n        std::string ftr;\n\n        std::string prog_name;\n        std::vector<std::string> others;\n        std::vector<std::string> errors;\n    };\n\n} // cmdline\n"
  },
  {
    "path": "ThirdParty/include/ini17/ini17.hpp",
    "content": "#include <type_traits>\n#include <unordered_map>\n#include <vector>\n#include <list>\n#include <optional>\n#include <fstream>\n#include <string>\n#include <sstream>\n#include <string_view>\n#include <cctype>\n#include <cstddef>\n\nnamespace ini17\n{\n    namespace detail\n    {\n        template <typename T>\n        struct is_string\n            : std::integral_constant<bool,\n                std::is_same_v<const char *, std::decay_t<T>>      ||\n                std::is_same_v<char *, std::decay_t<T>>            ||\n                std::is_same_v<std::string, std::decay_t<T>>       ||\n                std::is_same_v<std::string_view, std::decay_t<T>>> {};\n\n        template <typename T>\n        inline constexpr bool is_string_v = is_string<T>::value;\n        template <typename T>\n        inline constexpr bool not_string_v = !is_string_v<T>;\n\n        template <typename T>\n        inline T fromStringCast(const std::string &arg)\n        {\n            static std::istringstream iss;\n            T ret{};\n            iss.str(arg);\n            iss >> ret;\n            iss.clear();\n            return ret;\n        }\n\n        template <>\n        inline std::string fromStringCast<std::string>(const std::string &arg)\n        {\n            return arg;\n        }\n\n        template <typename T, std::enable_if_t<not_string_v<T>> * = nullptr>\n        inline std::string toStringCast(const T &arg)\n        {\n            return std::to_string(arg);\n        }\n\n        template <typename T, std::enable_if_t<is_string_v<T>> * = nullptr>\n        inline std::string toStringCast(const std::string &arg)\n        {\n            return arg;\n        }\n\n        enum class TokenType\n        {\n            Section,\n            Key,\n            Value,\n            Equal,\n            Bracket\n        };\n\n        struct Token\n        {\n            TokenType type;\n            std::string value;\n            std::size_t line;\n\n            Token(TokenType type, std::string_view value, std::size_t line)\n                : type(type), value(value), line(line) {}\n        };\n\n    } // namespace detail\n\n    using KeyValueType = std::unordered_map<std::string, std::string>;\n\n    class Section\n    {\n    private:\n        class KeyValueEditer\n        {\n        public:\n            KeyValueEditer(std::string &valueReference) : valueReference(valueReference) {}\n\n            template <typename T>\n            void operator=(const T &value)\n            {\n                valueReference = detail::toStringCast<T>(value);\n            }\n\n            template <typename T>\n            operator T() const\n            {\n                return detail::fromStringCast<T>(valueReference);\n            }\n\n            operator const std::string &() const\n            {\n                return valueReference;\n            }\n\n        private:\n            std::string &valueReference;\n        };\n\n    public:\n        Section(std::string_view name, KeyValueType kv) : name(name), kv(std::move(kv)) {}\n        Section(std::string_view name) : Section(name, KeyValueType{}) {}\n        Section(KeyValueType kv) : Section(std::string_view{}, std::move(kv)) {}\n        Section() : Section(std::string_view{}, KeyValueType{}) {}\n\n        void setName(std::string_view name)\n        {\n            this->name = name;\n        }\n\n        std::string_view getName() const\n        {\n            return name;\n        }\n\n        const KeyValueType &getKeyValueMap() const\n        {\n            return kv;\n        }\n\n        template <typename T>\n        std::optional<T> get(std::string_view key) const\n        {\n            auto vit = kv.find(key.data());\n            if (vit == kv.end())\n                return std::nullopt;\n            return detail::fromStringCast<T>(vit->second);\n        }\n\n        template <typename T>\n        bool set(std::string_view key, const T &value)\n        {\n            auto vit = kv.find(key.data());\n            if (vit == kv.end())\n                return false;\n            vit->second.assign(detail::toStringCast<T>(value));\n            return true;\n        }\n\n        template <typename T>\n        bool add(std::string_view key, const T &value)\n        {\n            return kv.emplace(key, detail::toStringCast<T>(value)).second;\n        }\n\n        KeyValueEditer operator[](std::string_view key)\n        {\n            auto vit = kv.find(key.data());\n            if (vit != kv.end())\n                return vit->second;\n            return kv.emplace(key, std::string{}).first->second;\n        }\n\n    private:\n        std::string name;\n        KeyValueType kv;\n    };\n\n    class Parser\n    {\n    public:\n        template <typename T>\n        std::optional<T> get(std::string_view name) const\n        {\n            if constexpr (std::is_same_v<T, Section>)\n            {\n                auto sit = result.find(name.data());\n                if (sit == result.end())\n                    return std::nullopt;\n                return Section{name, sit->second};\n            }\n            else\n            {\n                return get<T>(defaultSectionName, name);\n            }\n        }\n\n        template <typename T>\n        std::optional<T> get(std::string_view section, std::string_view key) const\n        {\n            auto sit = result.find(section.data());\n            if (sit == result.end())\n                return std::nullopt;\n            auto vit = sit->second.find(key.data());\n            if (vit == sit->second.end())\n                return std::nullopt;\n            return detail::fromStringCast<T>(vit->second);\n        }\n\n        bool parseFile(std::string_view filePath)\n        {\n            std::string contents;\n            std::ifstream file(filePath.data(), std::ios::in | std::ios::ate);\n            if (!file.is_open())\n                return false;\n            contents.resize(file.tellg());\n            file.seekg(0, std::ios::beg);\n            file.read(&contents[0], contents.size());\n            file.close();\n            return parse(contents);\n        }\n\n        bool parse(std::string_view src)\n        {\n            if (!result.empty())\n                result.clear();\n            auto tokens = tokenize(src);\n            if (!tokens.has_value())\n            {\n                pushError(\"Failed to parse source file.\");\n                return false;\n            }\n            analyze(*tokens);\n            return true;\n        }\n\n        const std::vector<std::string> &error() const\n        {\n            return errors;\n        }\n\n        void setDefaultSectionName(std::string_view section)\n        {\n            defaultSectionName = section;\n        }\n\n        std::string_view getDefaultSectionName() const\n        {\n            return defaultSectionName;\n        }\n\n    private:\n        template <typename Token>\n        void pushError(std::size_t line, Token token)\n        {\n            errors.emplace_back(\"error: \" + std::to_string(line) + \": unexcept token: \" + token);\n        }\n\n        void pushError(std::string_view err)\n        {\n            errors.emplace_back(err);\n        }\n\n    private:\n        std::optional<std::vector<detail::Token>> tokenize(std::string_view src)\n        {\n            std::vector<detail::Token> tokens;\n            auto length = src.size();\n            std::string_view::size_type count = 0;\n            std::size_t line = 1;\n\n            auto boundaryCheck = [this, length](std::size_t current) -> bool\n            {\n                if (current >= length)\n                {\n                    pushError(\"The source file cannot be resolved\");\n                    return false;\n                }\n\n                return true;\n            };\n\n            while (count < length)\n            {\n                char c = src[count];\n\n                if (c == '\\n')\n                {\n                    line++;\n                    count++;\n                    continue;\n                }\n\n                if (c == '#' || c == ';')\n                {\n                    do\n                        c = src[++count];\n                    while (c != '\\n' && count < length);\n\n                    count++;\n                    line++;\n                    continue;\n                }\n\n                if (c == '[')\n                {\n                    tokens.emplace_back(detail::TokenType::Bracket, \"[\", line);\n\n                    std::string section;\n\n                    while ((c = src[++count]) != ']' && !std::isspace(c) && count < length)\n                        section.push_back(c);\n\n                    if (!boundaryCheck(count))\n                        return std::nullopt;\n\n                    while (std::isspace(c))\n                    {\n                        if (c == '\\n')\n                        {\n                            pushError(line, c);\n                            return std::nullopt;\n                        }\n                        c = src[++count];\n                        if (!boundaryCheck(count))\n                            return std::nullopt;\n                    }\n\n                    if (c != ']')\n                    {\n                        pushError(line, c);\n                        return std::nullopt;\n                    }\n\n                    tokens.emplace_back(detail::TokenType::Section, section, line);\n                    tokens.emplace_back(detail::TokenType::Bracket, \"]\", line);\n                    count++;\n                    continue;\n                }\n\n                if (std::isgraph(c))\n                {\n                    std::string key{c};\n\n                    while ((c = src[++count]) != '=' && !std::isspace(c) && count < length)\n                        key.push_back(c);\n\n                    if (!boundaryCheck(count))\n                        return std::nullopt;\n\n                    while (std::isspace(c))\n                    {\n                        if (c == '\\n')\n                        {\n                            pushError(line, c);\n                            return std::nullopt;\n                        }\n                        c = src[++count];\n                        if (!boundaryCheck(count))\n                            return std::nullopt;\n                    }\n\n                    if (c != '=')\n                    {\n                        pushError(line, c);\n                        return std::nullopt;\n                    }\n\n                    tokens.emplace_back(detail::TokenType::Key, key, line);\n                    tokens.emplace_back(detail::TokenType::Equal, \"=\", line);\n\n                    while (std::isspace(c = src[++count]))\n                    {\n                        if (!boundaryCheck(count))\n                            return std::nullopt;\n                    }\n\n                    if (std::isgraph(c))\n                    {\n                        std::string value{c};\n                        for (;;)\n                        {\n                            while ((c = src[++count]) != '\\n' && !std::isspace(c) && count < length)\n                                value.push_back(c);\n\n                            if (!boundaryCheck(count))\n                                return std::nullopt;\n\n                            if (c != '\\n')\n                            {\n                                std::string buf{c};\n\n                                do\n                                {\n                                    buf.push_back(c = src[++count]);\n                                    if (!boundaryCheck(count))\n                                        return std::nullopt;\n                                } while (c != '\\n' && std::isspace(c));\n\n                                if (c != '\\n')\n                                    value.append(buf);\n                                else\n                                    break;\n                            }\n                            else\n                                break;\n                        };\n\n                        tokens.emplace_back(detail::TokenType::Value, value, line);\n                        line++;\n                        count++;\n                        continue;\n                    }\n                }\n                count++;\n            }\n\n            return std::make_optional(tokens);\n        }\n\n        void analyze(const std::vector<detail::Token> &tokens)\n        {\n            auto length = tokens.size();\n            std::vector<detail::Token>::size_type count = 0;\n\n            ResultType::iterator it;\n\n            auto boundaryCheck = [this, length](std::size_t current) -> bool\n            {\n                if (current >= length)\n                {\n                    pushError(\"The token list cannot be resolved\");\n                    return false;\n                }\n\n                return true;\n            };\n\n            if (length && tokens.front().type != detail::TokenType::Bracket)\n            {\n                it = result.emplace(defaultSectionName, KeyValueType{}).first;\n            }\n\n            while (count < length)\n            {\n                if (tokens[count].type == detail::TokenType::Bracket)\n                {\n                    if (!boundaryCheck(count + 2))\n                        return;\n\n                    auto &lBracketToken = tokens[count];\n                    auto &sectionToken = tokens[count + 1];\n                    auto &rBracketToken = tokens[count + 2];\n\n                    if (sectionToken.type != detail::TokenType::Section || rBracketToken.type != detail::TokenType::Bracket)\n                    {\n                        pushError(lBracketToken.line, lBracketToken.value);\n                        return;\n                    }\n\n                    it = result.emplace(sectionToken.value, KeyValueType{}).first;\n\n                    count += 3;\n                    continue;\n                }\n\n                if (tokens[count].type == detail::TokenType::Key)\n                {\n                    if (!boundaryCheck(count + 2))\n                        return;\n\n                    auto &keyToken = tokens[count];\n                    auto &equalToken = tokens[count + 1];\n                    auto &valueToken = tokens[count + 2];\n\n                    if (equalToken.type != detail::TokenType::Equal || valueToken.type != detail::TokenType::Value)\n                    {\n                        pushError(keyToken.line, keyToken.value);\n                        return;\n                    }\n\n                    auto &&ret = it->second.emplace(keyToken.value, valueToken.value);\n                    if (!ret.second)\n                        pushError(\"duplicate key: \" + tokens[count].value + \", in section: \" + it->first);\n\n                    count += 3;\n                    continue;\n                }\n                count++;\n            }\n        }\n\n    private:\n        using ResultType = std::unordered_map<std::string, KeyValueType>;\n\n        ResultType result;\n        std::vector<std::string> errors;\n        std::string defaultSectionName = \"global\";\n    };\n\n    class Generator\n    {\n    public:\n        template <typename... Sections>\n        std::enable_if_t<std::conjunction_v<std::is_same<Section, std::remove_reference_t<Sections>>...>>\n        push(Sections &&...args)\n        {\n            (sections.emplace_back(std::forward<Sections>(args)), ...);\n        }\n\n        template <typename... Args>\n        std::enable_if_t<std::disjunction_v<std::negation<std::is_same<Section, std::remove_reference_t<Args>>>...>>\n        push(Args &&...args)\n        {\n            sections.emplace_back(std::forward<Args>(args)...);\n        }\n\n        void clear() noexcept\n        {\n            sections.clear();\n        }\n\n        void setHeader(std::string_view msg)\n        {\n            header = msg;\n        }\n\n        void setFooter(std::string_view msg)\n        {\n            footer = msg;\n        }\n\n        bool generateFile(std::string_view filePath) const\n        {\n            std::ofstream file(filePath.data());\n            if (!file.is_open())\n                return false;\n            file << generate();\n            file.close();\n            return true;\n        }\n\n        std::string generate() const\n        {\n            std::string ret;\n            if (!header.empty())\n            {\n                ret.push_back(';');\n                ret.append(header).append(\"\\n\\n\");\n            }\n            for (auto &&section : sections)\n            {\n                auto &&kvMap = section.getKeyValueMap();\n                auto name = section.getName();\n                if (!name.empty())\n                {\n                    ret.push_back('[');\n                    ret.append(name);\n                    ret.push_back(']');\n                    ret.push_back('\\n');\n                }\n                for (auto &&kv : kvMap)\n                {\n                    ret.append(kv.first).append(\" = \").append(kv.second).push_back('\\n');\n                }\n                ret.push_back('\\n');\n            }\n            if (!footer.empty())\n            {\n                ret.push_back(';');\n                ret.append(footer);\n                ret.push_back('\\n');\n            }\n            return ret;\n        }\n\n    private:\n        std::string header;\n        std::string footer;\n        std::list<Section> sections;\n    };\n\n} // namespace ini17\n"
  },
  {
    "path": "ThirdParty/include/opencl/CL/opencl.hpp",
    "content": "//\n// Copyright (c) 2008-2020 The Khronos Group Inc.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//    http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n\n/*! \\file\n *\n *   \\brief C++ bindings for OpenCL 1.0, OpenCL 1.1, OpenCL 1.2,\n *       OpenCL 2.0, OpenCL 2.1, OpenCL 2.2, and OpenCL 3.0.\n *   \\author Lee Howes and Bruce Merry\n *\n *   Derived from the OpenCL 1.x C++ bindings written by\n *   Benedict R. Gaster, Laurent Morichetti and Lee Howes\n *   With additions and fixes from:\n *       Brian Cole, March 3rd 2010 and April 2012\n *       Matt Gruenke, April 2012.\n *       Bruce Merry, February 2013.\n *       Tom Deakin and Simon McIntosh-Smith, July 2013\n *       James Price, 2015-\n *   \\version 2.2.0\n *   \\date 2019-09-18\n *\n *   Optional extension support\n *\n *         cl_ext_device_fission\n *         #define CL_HPP_USE_CL_DEVICE_FISSION\n *         cl_khr_d3d10_sharing\n *         #define CL_HPP_USE_DX_INTEROP\n *         cl_khr_sub_groups\n *         #define CL_HPP_USE_CL_SUB_GROUPS_KHR\n *         cl_khr_image2d_from_buffer\n *         #define CL_HPP_USE_CL_IMAGE2D_FROM_BUFFER_KHR\n *\n *   Doxygen documentation for this header is available here:\n *\n *       http://khronosgroup.github.io/OpenCL-CLHPP/\n *\n *   The latest version of this header can be found on the GitHub releases page:\n *\n *       https://github.com/KhronosGroup/OpenCL-CLHPP/releases\n *\n *   Bugs and patches can be submitted to the GitHub repository:\n *\n *       https://github.com/KhronosGroup/OpenCL-CLHPP\n */\n\n/*! \\mainpage\n * \\section intro Introduction\n * For many large applications C++ is the language of choice and so it seems\n * reasonable to define C++ bindings for OpenCL.\n *\n * The interface is contained with a single C++ header file \\em opencl.hpp and all\n * definitions are contained within the namespace \\em cl. There is no additional\n * requirement to include \\em cl.h and to use either the C++ or original C\n * bindings; it is enough to simply include \\em opencl.hpp.\n *\n * The bindings themselves are lightweight and correspond closely to the\n * underlying C API. Using the C++ bindings introduces no additional execution\n * overhead.\n *\n * There are numerous compatibility, portability and memory management\n * fixes in the new header as well as additional OpenCL 2.0 features.\n * As a result the header is not directly backward compatible and for this\n * reason we release it as opencl.hpp rather than a new version of cl.hpp.\n * \n *\n * \\section compatibility Compatibility\n * Due to the evolution of the underlying OpenCL API the 2.0 C++ bindings\n * include an updated approach to defining supported feature versions\n * and the range of valid underlying OpenCL runtime versions supported.\n *\n * The combination of preprocessor macros CL_HPP_TARGET_OPENCL_VERSION and \n * CL_HPP_MINIMUM_OPENCL_VERSION control this range. These are three digit\n * decimal values representing OpenCL runime versions. The default for \n * the target is 200, representing OpenCL 2.0 and the minimum is also \n * defined as 200. These settings would use 2.0 API calls only.\n * If backward compatibility with a 1.2 runtime is required, the minimum\n * version may be set to 120.\n *\n * Note that this is a compile-time setting, and so affects linking against\n * a particular SDK version rather than the versioning of the loaded runtime.\n *\n * The earlier versions of the header included basic vector and string \n * classes based loosely on STL versions. These were difficult to \n * maintain and very rarely used. For the 2.0 header we now assume\n * the presence of the standard library unless requested otherwise.\n * We use std::array, std::vector, std::shared_ptr and std::string \n * throughout to safely manage memory and reduce the chance of a \n * recurrance of earlier memory management bugs.\n *\n * These classes are used through typedefs in the cl namespace: \n * cl::array, cl::vector, cl::pointer and cl::string.\n * In addition cl::allocate_pointer forwards to std::allocate_shared\n * by default.\n * In all cases these standard library classes can be replaced with \n * custom interface-compatible versions using the CL_HPP_NO_STD_ARRAY, \n * CL_HPP_NO_STD_VECTOR, CL_HPP_NO_STD_UNIQUE_PTR and \n * CL_HPP_NO_STD_STRING macros.\n *\n * The OpenCL 1.x versions of the C++ bindings included a size_t wrapper\n * class to interface with kernel enqueue. This caused unpleasant interactions\n * with the standard size_t declaration and led to namespacing bugs.\n * In the 2.0 version we have replaced this with a std::array-based interface.\n * However, the old behaviour can be regained for backward compatibility\n * using the CL_HPP_ENABLE_SIZE_T_COMPATIBILITY macro.\n *\n * Finally, the program construction interface used a clumsy vector-of-pairs\n * design in the earlier versions. We have replaced that with a cleaner \n * vector-of-vectors and vector-of-strings design. However, for backward \n * compatibility old behaviour can be regained with the\n * CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY macro.\n * \n * In OpenCL 2.0 OpenCL C is not entirely backward compatibility with \n * earlier versions. As a result a flag must be passed to the OpenCL C\n * compiled to request OpenCL 2.0 compilation of kernels with 1.2 as\n * the default in the absence of the flag.\n * In some cases the C++ bindings automatically compile code for ease.\n * For those cases the compilation defaults to OpenCL C 2.0.\n * If this is not wanted, the CL_HPP_CL_1_2_DEFAULT_BUILD macro may\n * be specified to assume 1.2 compilation.\n * If more fine-grained decisions on a per-kernel bases are required\n * then explicit build operations that take the flag should be used.\n *\n *\n * \\section parameterization Parameters\n * This header may be parameterized by a set of preprocessor macros.\n *\n * - CL_HPP_TARGET_OPENCL_VERSION\n *\n *   Defines the target OpenCL runtime version to build the header\n *   against. Defaults to 200, representing OpenCL 2.0.\n *\n * - CL_HPP_NO_STD_STRING\n *\n *   Do not use the standard library string class. cl::string is not\n *   defined and may be defined by the user before opencl.hpp is\n *   included.\n *\n * - CL_HPP_NO_STD_VECTOR\n *\n *   Do not use the standard library vector class. cl::vector is not\n *   defined and may be defined by the user before opencl.hpp is\n *   included.\n *\n * - CL_HPP_NO_STD_ARRAY\n *\n *   Do not use the standard library array class. cl::array is not\n *   defined and may be defined by the user before opencl.hpp is\n *   included.\n *\n * - CL_HPP_NO_STD_UNIQUE_PTR\n *\n *   Do not use the standard library unique_ptr class. cl::pointer and\n *   the cl::allocate_pointer functions are not defined and may be\n *   defined by the user before opencl.hpp is included.\n *\n * - CL_HPP_ENABLE_DEVICE_FISSION\n *\n *   Enables device fission for OpenCL 1.2 platforms.\n *\n * - CL_HPP_ENABLE_EXCEPTIONS\n *\n *   Enable exceptions for use in the C++ bindings header. This is the\n *   preferred error handling mechanism but is not required.\n *\n * - CL_HPP_ENABLE_SIZE_T_COMPATIBILITY\n *\n *   Backward compatibility option to support cl.hpp-style size_t\n *   class.  Replaces the updated std::array derived version and\n *   removal of size_t from the namespace. Note that in this case the\n *   new size_t class is placed in the cl::compatibility namespace and\n *   thus requires an additional using declaration for direct backward\n *   compatibility.\n *\n * - CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY\n *\n *   Enable older vector of pairs interface for construction of\n *   programs.\n *\n * - CL_HPP_CL_1_2_DEFAULT_BUILD\n *\n *   Default to OpenCL C 1.2 compilation rather than OpenCL C 2.0\n *   applies to use of cl::Program construction and other program\n *   build variants.\n *\n * - CL_HPP_USE_CL_SUB_GROUPS_KHR\n *\n *   Enable the cl_khr_subgroups extension.\n *\n * - CL_HPP_USE_IL_KHR\n *\n *   Enable the cl_khr_il_program extension.\n *\n *\n * \\section example Example\n *\n * The following example shows a general use case for the C++\n * bindings, including support for the optional exception feature and\n * also the supplied vector and string classes, see following sections for\n * decriptions of these features.\n *\n * \\code\n    #define CL_HPP_ENABLE_EXCEPTIONS\n    #define CL_HPP_TARGET_OPENCL_VERSION 200\n\n    #include <CL/opencl.hpp>\n    #include <iostream>\n    #include <vector>\n    #include <memory>\n    #include <algorithm>\n\n    const int numElements = 32;\n\n    int main(void)\n    {\n        // Filter for a 2.0 platform and set it as the default\n        std::vector<cl::Platform> platforms;\n        cl::Platform::get(&platforms);\n        cl::Platform plat;\n        for (auto &p : platforms) {\n            std::string platver = p.getInfo<CL_PLATFORM_VERSION>();\n            if (platver.find(\"OpenCL 2.\") != std::string::npos) {\n                plat = p;\n            }\n        }\n        if (plat() == 0)  {\n            std::cout << \"No OpenCL 2.0 platform found.\";\n            return -1;\n        }\n\n        cl::Platform newP = cl::Platform::setDefault(plat);\n        if (newP != plat) {\n            std::cout << \"Error setting default platform.\";\n            return -1;\n        }\n\n        // Use C++11 raw string literals for kernel source code\n        std::string kernel1{R\"CLC(\n            global int globalA;\n            kernel void updateGlobal()\n            {\n              globalA = 75;\n            }\n        )CLC\"};\n        std::string kernel2{R\"CLC(\n            typedef struct { global int *bar; } Foo;\n            kernel void vectorAdd(global const Foo* aNum, global const int *inputA, global const int *inputB,\n                                  global int *output, int val, write_only pipe int outPipe, queue_t childQueue)\n            {\n              output[get_global_id(0)] = inputA[get_global_id(0)] + inputB[get_global_id(0)] + val + *(aNum->bar);\n              write_pipe(outPipe, &val);\n              queue_t default_queue = get_default_queue();\n              ndrange_t ndrange = ndrange_1D(get_global_size(0)/2, get_global_size(0)/2);\n\n              // Have a child kernel write into third quarter of output\n              enqueue_kernel(default_queue, CLK_ENQUEUE_FLAGS_WAIT_KERNEL, ndrange,\n                ^{\n                    output[get_global_size(0)*2 + get_global_id(0)] =\n                      inputA[get_global_size(0)*2 + get_global_id(0)] + inputB[get_global_size(0)*2 + get_global_id(0)] + globalA;\n                });\n\n              // Have a child kernel write into last quarter of output\n              enqueue_kernel(childQueue, CLK_ENQUEUE_FLAGS_WAIT_KERNEL, ndrange,\n                ^{\n                    output[get_global_size(0)*3 + get_global_id(0)] =\n                      inputA[get_global_size(0)*3 + get_global_id(0)] + inputB[get_global_size(0)*3 + get_global_id(0)] + globalA + 2;\n                });\n            }\n        )CLC\"};\n\n        // New simpler string interface style\n        std::vector<std::string> programStrings {kernel1, kernel2};\n\n        cl::Program vectorAddProgram(programStrings);\n        try {\n            vectorAddProgram.build(\"-cl-std=CL2.0\");\n        }\n        catch (...) {\n            // Print build info for all devices\n            cl_int buildErr = CL_SUCCESS;\n            auto buildInfo = vectorAddProgram.getBuildInfo<CL_PROGRAM_BUILD_LOG>(&buildErr);\n            for (auto &pair : buildInfo) {\n                std::cerr << pair.second << std::endl << std::endl;\n            }\n\n            return 1;\n        }\n\n        typedef struct { int *bar; } Foo;\n\n        // Get and run kernel that initializes the program-scope global\n        // A test for kernels that take no arguments\n        auto program2Kernel =\n            cl::KernelFunctor<>(vectorAddProgram, \"updateGlobal\");\n        program2Kernel(\n            cl::EnqueueArgs(\n            cl::NDRange(1)));\n\n        //////////////////\n        // SVM allocations\n\n        auto anSVMInt = cl::allocate_svm<int, cl::SVMTraitCoarse<>>();\n        *anSVMInt = 5;\n        cl::SVMAllocator<Foo, cl::SVMTraitCoarse<cl::SVMTraitReadOnly<>>> svmAllocReadOnly;\n        auto fooPointer = cl::allocate_pointer<Foo>(svmAllocReadOnly);\n        fooPointer->bar = anSVMInt.get();\n        cl::SVMAllocator<int, cl::SVMTraitCoarse<>> svmAlloc;\n        std::vector<int, cl::SVMAllocator<int, cl::SVMTraitCoarse<>>> inputA(numElements, 1, svmAlloc);\n        cl::coarse_svm_vector<int> inputB(numElements, 2, svmAlloc);\n\n        //\n        //////////////\n\n        // Traditional cl_mem allocations\n        std::vector<int> output(numElements, 0xdeadbeef);\n        cl::Buffer outputBuffer(begin(output), end(output), false);\n        cl::Pipe aPipe(sizeof(cl_int), numElements / 2);\n\n        // Default command queue, also passed in as a parameter\n        cl::DeviceCommandQueue defaultDeviceQueue = cl::DeviceCommandQueue::makeDefault(\n            cl::Context::getDefault(), cl::Device::getDefault());\n\n        auto vectorAddKernel =\n            cl::KernelFunctor<\n                decltype(fooPointer)&,\n                int*,\n                cl::coarse_svm_vector<int>&,\n                cl::Buffer,\n                int,\n                cl::Pipe&,\n                cl::DeviceCommandQueue\n                >(vectorAddProgram, \"vectorAdd\");\n\n        // Ensure that the additional SVM pointer is available to the kernel\n        // This one was not passed as a parameter\n        vectorAddKernel.setSVMPointers(anSVMInt);\n\n        // Hand control of coarse allocations to runtime\n        cl::enqueueUnmapSVM(anSVMInt);\n        cl::enqueueUnmapSVM(fooPointer);\n        cl::unmapSVM(inputB);\n        cl::unmapSVM(output2);\n\n\t    cl_int error;\n\t    vectorAddKernel(\n            cl::EnqueueArgs(\n                cl::NDRange(numElements/2),\n                cl::NDRange(numElements/2)),\n            fooPointer,\n            inputA.data(),\n            inputB,\n            outputBuffer,\n            3,\n            aPipe,\n            defaultDeviceQueue,\n\t\t    error\n            );\n\n        cl::copy(outputBuffer, begin(output), end(output));\n        // Grab the SVM output vector using a map\n        cl::mapSVM(output2);\n\n        cl::Device d = cl::Device::getDefault();\n\n        std::cout << \"Output:\\n\";\n        for (int i = 1; i < numElements; ++i) {\n            std::cout << \"\\t\" << output[i] << \"\\n\";\n        }\n        std::cout << \"\\n\\n\";\n\n        return 0;\n    }\n *\n * \\endcode\n *\n */\n#ifndef CL_HPP_\n#define CL_HPP_\n\n/* Handle deprecated preprocessor definitions. In each case, we only check for\n * the old name if the new name is not defined, so that user code can define\n * both and hence work with either version of the bindings.\n */\n#if !defined(CL_HPP_USE_DX_INTEROP) && defined(USE_DX_INTEROP)\n# pragma message(\"opencl.hpp: USE_DX_INTEROP is deprecated. Define CL_HPP_USE_DX_INTEROP instead\")\n# define CL_HPP_USE_DX_INTEROP\n#endif\n#if !defined(CL_HPP_USE_CL_DEVICE_FISSION) && defined(USE_CL_DEVICE_FISSION)\n# pragma message(\"opencl.hpp: USE_CL_DEVICE_FISSION is deprecated. Define CL_HPP_USE_CL_DEVICE_FISSION instead\")\n# define CL_HPP_USE_CL_DEVICE_FISSION\n#endif\n#if !defined(CL_HPP_ENABLE_EXCEPTIONS) && defined(__CL_ENABLE_EXCEPTIONS)\n# pragma message(\"opencl.hpp: __CL_ENABLE_EXCEPTIONS is deprecated. Define CL_HPP_ENABLE_EXCEPTIONS instead\")\n# define CL_HPP_ENABLE_EXCEPTIONS\n#endif\n#if !defined(CL_HPP_NO_STD_VECTOR) && defined(__NO_STD_VECTOR)\n# pragma message(\"opencl.hpp: __NO_STD_VECTOR is deprecated. Define CL_HPP_NO_STD_VECTOR instead\")\n# define CL_HPP_NO_STD_VECTOR\n#endif\n#if !defined(CL_HPP_NO_STD_STRING) && defined(__NO_STD_STRING)\n# pragma message(\"opencl.hpp: __NO_STD_STRING is deprecated. Define CL_HPP_NO_STD_STRING instead\")\n# define CL_HPP_NO_STD_STRING\n#endif\n#if defined(VECTOR_CLASS)\n# pragma message(\"opencl.hpp: VECTOR_CLASS is deprecated. Alias cl::vector instead\")\n#endif\n#if defined(STRING_CLASS)\n# pragma message(\"opencl.hpp: STRING_CLASS is deprecated. Alias cl::string instead.\")\n#endif\n#if !defined(CL_HPP_USER_OVERRIDE_ERROR_STRINGS) && defined(__CL_USER_OVERRIDE_ERROR_STRINGS)\n# pragma message(\"opencl.hpp: __CL_USER_OVERRIDE_ERROR_STRINGS is deprecated. Define CL_HPP_USER_OVERRIDE_ERROR_STRINGS instead\")\n# define CL_HPP_USER_OVERRIDE_ERROR_STRINGS\n#endif\n\n/* Warn about features that are no longer supported\n */\n#if defined(__USE_DEV_VECTOR)\n# pragma message(\"opencl.hpp: __USE_DEV_VECTOR is no longer supported. Expect compilation errors\")\n#endif\n#if defined(__USE_DEV_STRING)\n# pragma message(\"opencl.hpp: __USE_DEV_STRING is no longer supported. Expect compilation errors\")\n#endif\n\n/* Detect which version to target */\n#if !defined(CL_HPP_TARGET_OPENCL_VERSION)\n# pragma message(\"opencl.hpp: CL_HPP_TARGET_OPENCL_VERSION is not defined. It will default to 300 (OpenCL 3.0)\")\n# define CL_HPP_TARGET_OPENCL_VERSION 300\n#endif\n#if CL_HPP_TARGET_OPENCL_VERSION != 100 && \\\n    CL_HPP_TARGET_OPENCL_VERSION != 110 && \\\n    CL_HPP_TARGET_OPENCL_VERSION != 120 && \\\n    CL_HPP_TARGET_OPENCL_VERSION != 200 && \\\n    CL_HPP_TARGET_OPENCL_VERSION != 210 && \\\n    CL_HPP_TARGET_OPENCL_VERSION != 220 && \\\n    CL_HPP_TARGET_OPENCL_VERSION != 300\n# pragma message(\"opencl.hpp: CL_HPP_TARGET_OPENCL_VERSION is not a valid value (100, 110, 120, 200, 210, 220 or 300). It will be set to 300 (OpenCL 3.0).\")\n# undef CL_HPP_TARGET_OPENCL_VERSION\n# define CL_HPP_TARGET_OPENCL_VERSION 300\n#endif\n\n/* Forward target OpenCL version to C headers if necessary */\n#if defined(CL_TARGET_OPENCL_VERSION)\n/* Warn if prior definition of CL_TARGET_OPENCL_VERSION is lower than\n * requested C++ bindings version */\n#if CL_TARGET_OPENCL_VERSION < CL_HPP_TARGET_OPENCL_VERSION\n# pragma message(\"CL_TARGET_OPENCL_VERSION is already defined as is lower than CL_HPP_TARGET_OPENCL_VERSION\")\n#endif\n#else\n# define CL_TARGET_OPENCL_VERSION CL_HPP_TARGET_OPENCL_VERSION\n#endif\n\n#if !defined(CL_HPP_MINIMUM_OPENCL_VERSION)\n# define CL_HPP_MINIMUM_OPENCL_VERSION 200\n#endif\n#if CL_HPP_MINIMUM_OPENCL_VERSION != 100 && \\\n    CL_HPP_MINIMUM_OPENCL_VERSION != 110 && \\\n    CL_HPP_MINIMUM_OPENCL_VERSION != 120 && \\\n    CL_HPP_MINIMUM_OPENCL_VERSION != 200 && \\\n    CL_HPP_MINIMUM_OPENCL_VERSION != 210 && \\\n    CL_HPP_MINIMUM_OPENCL_VERSION != 220 && \\\n    CL_HPP_MINIMUM_OPENCL_VERSION != 300\n# pragma message(\"opencl.hpp: CL_HPP_MINIMUM_OPENCL_VERSION is not a valid value (100, 110, 120, 200, 210, 220 or 300). It will be set to 100\")\n# undef CL_HPP_MINIMUM_OPENCL_VERSION\n# define CL_HPP_MINIMUM_OPENCL_VERSION 100\n#endif\n#if CL_HPP_MINIMUM_OPENCL_VERSION > CL_HPP_TARGET_OPENCL_VERSION\n# error \"CL_HPP_MINIMUM_OPENCL_VERSION must not be greater than CL_HPP_TARGET_OPENCL_VERSION\"\n#endif\n\n#if CL_HPP_MINIMUM_OPENCL_VERSION <= 100 && !defined(CL_USE_DEPRECATED_OPENCL_1_0_APIS)\n# define CL_USE_DEPRECATED_OPENCL_1_0_APIS\n#endif\n#if CL_HPP_MINIMUM_OPENCL_VERSION <= 110 && !defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS)\n# define CL_USE_DEPRECATED_OPENCL_1_1_APIS\n#endif\n#if CL_HPP_MINIMUM_OPENCL_VERSION <= 120 && !defined(CL_USE_DEPRECATED_OPENCL_1_2_APIS)\n# define CL_USE_DEPRECATED_OPENCL_1_2_APIS\n#endif\n#if CL_HPP_MINIMUM_OPENCL_VERSION <= 200 && !defined(CL_USE_DEPRECATED_OPENCL_2_0_APIS)\n# define CL_USE_DEPRECATED_OPENCL_2_0_APIS\n#endif\n#if CL_HPP_MINIMUM_OPENCL_VERSION <= 210 && !defined(CL_USE_DEPRECATED_OPENCL_2_1_APIS)\n# define CL_USE_DEPRECATED_OPENCL_2_1_APIS\n#endif\n#if CL_HPP_MINIMUM_OPENCL_VERSION <= 220 && !defined(CL_USE_DEPRECATED_OPENCL_2_2_APIS)\n# define CL_USE_DEPRECATED_OPENCL_2_2_APIS\n#endif\n\n#ifdef _WIN32\n\n#include <malloc.h>\n\n#if defined(CL_HPP_USE_DX_INTEROP)\n#include <CL/cl_d3d10.h>\n#include <CL/cl_dx9_media_sharing.h>\n#endif\n#endif // _WIN32\n\n#if defined(_MSC_VER)\n#include <intrin.h>\n#endif // _MSC_VER \n \n // Check for a valid C++ version\n\n// Need to do both tests here because for some reason __cplusplus is not \n// updated in visual studio\n#if (!defined(_MSC_VER) && __cplusplus < 201103L) || (defined(_MSC_VER) && _MSC_VER < 1700)\n#error Visual studio 2013 or another C++11-supporting compiler required\n#endif\n\n// \n#if defined(CL_HPP_USE_CL_DEVICE_FISSION) || defined(CL_HPP_USE_CL_SUB_GROUPS_KHR)\n#include <CL/cl_ext.h>\n#endif\n\n#if defined(__APPLE__) || defined(__MACOSX)\n#include <OpenCL/opencl.h>\n#else\n#include <CL/opencl.h>\n#endif // !__APPLE__\n\n#if (__cplusplus >= 201103L || _MSVC_LANG >= 201103L )\n#define CL_HPP_NOEXCEPT_ noexcept\n#else\n#define CL_HPP_NOEXCEPT_\n#endif\n\n#if __cplusplus >= 201703L\n# define CL_HPP_DEFINE_STATIC_MEMBER_ inline\n#elif defined(_MSC_VER)\n# define CL_HPP_DEFINE_STATIC_MEMBER_ __declspec(selectany)\n#elif defined(__MINGW32__)\n# define CL_HPP_DEFINE_STATIC_MEMBER_ __attribute__((selectany))\n#else\n# define CL_HPP_DEFINE_STATIC_MEMBER_ __attribute__((weak))\n#endif // !_MSC_VER\n\n// Define deprecated prefixes and suffixes to ensure compilation\n// in case they are not pre-defined\n#if !defined(CL_API_PREFIX__VERSION_1_1_DEPRECATED)\n#define CL_API_PREFIX__VERSION_1_1_DEPRECATED  \n#endif // #if !defined(CL_API_PREFIX__VERSION_1_1_DEPRECATED)\n#if !defined(CL_API_SUFFIX__VERSION_1_1_DEPRECATED)\n#define CL_API_SUFFIX__VERSION_1_1_DEPRECATED\n#endif // #if !defined(CL_API_PREFIX__VERSION_1_1_DEPRECATED)\n\n#if !defined(CL_API_PREFIX__VERSION_1_2_DEPRECATED)\n#define CL_API_PREFIX__VERSION_1_2_DEPRECATED  \n#endif // #if !defined(CL_API_PREFIX__VERSION_1_2_DEPRECATED)\n#if !defined(CL_API_SUFFIX__VERSION_1_2_DEPRECATED)\n#define CL_API_SUFFIX__VERSION_1_2_DEPRECATED\n#endif // #if !defined(CL_API_PREFIX__VERSION_1_2_DEPRECATED)\n\n#if !defined(CL_CALLBACK)\n#define CL_CALLBACK\n#endif //CL_CALLBACK\n\n#include <utility>\n#include <limits>\n#include <iterator>\n#include <mutex>\n#include <cstring>\n#include <functional>\n\n\n// Define a size_type to represent a correctly resolved size_t\n#if defined(CL_HPP_ENABLE_SIZE_T_COMPATIBILITY)\nnamespace cl {\n    using size_type = ::size_t;\n} // namespace cl\n#else // #if defined(CL_HPP_ENABLE_SIZE_T_COMPATIBILITY)\nnamespace cl {\n    using size_type = size_t;\n} // namespace cl\n#endif // #if defined(CL_HPP_ENABLE_SIZE_T_COMPATIBILITY)\n\n\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n#include <exception>\n#endif // #if defined(CL_HPP_ENABLE_EXCEPTIONS)\n\n#if !defined(CL_HPP_NO_STD_VECTOR)\n#include <vector>\nnamespace cl {\n    template < class T, class Alloc = std::allocator<T> >\n    using vector = std::vector<T, Alloc>;\n} // namespace cl\n#endif // #if !defined(CL_HPP_NO_STD_VECTOR)\n\n#if !defined(CL_HPP_NO_STD_STRING)\n#include <string>\nnamespace cl {\n    using string = std::string;\n} // namespace cl\n#endif // #if !defined(CL_HPP_NO_STD_STRING)\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\n#if !defined(CL_HPP_NO_STD_UNIQUE_PTR)\n#include <memory>\nnamespace cl {\n    // Replace unique_ptr and allocate_pointer for internal use\n    // to allow user to replace them\n    template<class T, class D>\n    using pointer = std::unique_ptr<T, D>;\n} // namespace cl\n#endif \n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n#if !defined(CL_HPP_NO_STD_ARRAY)\n#include <array>\nnamespace cl {\n    template < class T, size_type N >\n    using array = std::array<T, N>;\n} // namespace cl\n#endif // #if !defined(CL_HPP_NO_STD_ARRAY)\n\n// Define size_type appropriately to allow backward-compatibility\n// use of the old size_t interface class\n#if defined(CL_HPP_ENABLE_SIZE_T_COMPATIBILITY)\nnamespace cl {\n    namespace compatibility {\n        /*! \\brief class used to interface between C++ and\n        *  OpenCL C calls that require arrays of size_t values, whose\n        *  size is known statically.\n        */\n        template <int N>\n        class size_t\n        {\n        private:\n            size_type data_[N];\n\n        public:\n            //! \\brief Initialize size_t to all 0s\n            size_t()\n            {\n                for (int i = 0; i < N; ++i) {\n                    data_[i] = 0;\n                }\n            }\n\n            size_t(const array<size_type, N> &rhs)\n            {\n                for (int i = 0; i < N; ++i) {\n                    data_[i] = rhs[i];\n                }\n            }\n\n            size_type& operator[](int index)\n            {\n                return data_[index];\n            }\n\n            const size_type& operator[](int index) const\n            {\n                return data_[index];\n            }\n\n            //! \\brief Conversion operator to T*.\n            operator size_type* ()             { return data_; }\n\n            //! \\brief Conversion operator to const T*.\n            operator const size_type* () const { return data_; }\n\n            operator array<size_type, N>() const\n            {\n                array<size_type, N> ret;\n\n                for (int i = 0; i < N; ++i) {\n                    ret[i] = data_[i];\n                }\n                return ret;\n            }\n        };\n    } // namespace compatibility\n\n    template<int N>\n    using size_t = compatibility::size_t<N>;\n} // namespace cl\n#endif // #if defined(CL_HPP_ENABLE_SIZE_T_COMPATIBILITY)\n\n// Helper alias to avoid confusing the macros\nnamespace cl {\n    namespace detail {\n        using size_t_array = array<size_type, 3>;\n    } // namespace detail\n} // namespace cl\n\n\n/*! \\namespace cl\n *\n * \\brief The OpenCL C++ bindings are defined within this namespace.\n *\n */\nnamespace cl {\n    class Memory;\n\n#define CL_HPP_INIT_CL_EXT_FCN_PTR_(name) \\\n    if (!pfn_##name) {    \\\n    pfn_##name = (PFN_##name) \\\n    clGetExtensionFunctionAddress(#name); \\\n    if (!pfn_##name) {    \\\n    } \\\n    }\n\n#define CL_HPP_INIT_CL_EXT_FCN_PTR_PLATFORM_(platform, name) \\\n    if (!pfn_##name) {    \\\n    pfn_##name = (PFN_##name) \\\n    clGetExtensionFunctionAddressForPlatform(platform, #name); \\\n    if (!pfn_##name) {    \\\n    } \\\n    }\n\n    class Program;\n    class Device;\n    class Context;\n    class CommandQueue;\n    class DeviceCommandQueue;\n    class Memory;\n    class Buffer;\n    class Pipe;\n\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n    /*! \\brief Exception class \n     * \n     *  This may be thrown by API functions when CL_HPP_ENABLE_EXCEPTIONS is defined.\n     */\n    class Error : public std::exception\n    {\n    private:\n        cl_int err_;\n        const char * errStr_;\n    public:\n        /*! \\brief Create a new CL error exception for a given error code\n         *  and corresponding message.\n         * \n         *  \\param err error code value.\n         *\n         *  \\param errStr a descriptive string that must remain in scope until\n         *                handling of the exception has concluded.  If set, it\n         *                will be returned by what().\n         */\n        Error(cl_int err, const char * errStr = NULL) : err_(err), errStr_(errStr)\n        {}\n\n        ~Error() throw() {}\n\n        /*! \\brief Get error string associated with exception\n         *\n         * \\return A memory pointer to the error message string.\n         */\n        virtual const char * what() const throw ()\n        {\n            if (errStr_ == NULL) {\n                return \"empty\";\n            }\n            else {\n                return errStr_;\n            }\n        }\n\n        /*! \\brief Get error code associated with exception\n         *\n         *  \\return The error code.\n         */\n        cl_int err(void) const { return err_; }\n    };\n#define CL_HPP_ERR_STR_(x) #x\n#else\n#define CL_HPP_ERR_STR_(x) NULL\n#endif // CL_HPP_ENABLE_EXCEPTIONS\n\n\nnamespace detail\n{\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\nstatic inline cl_int errHandler (\n    cl_int err,\n    const char * errStr = NULL)\n{\n    if (err != CL_SUCCESS) {\n        throw Error(err, errStr);\n    }\n    return err;\n}\n#else\nstatic inline cl_int errHandler (cl_int err, const char * errStr = NULL)\n{\n    (void) errStr; // suppress unused variable warning\n    return err;\n}\n#endif // CL_HPP_ENABLE_EXCEPTIONS\n}\n\n\n\n//! \\cond DOXYGEN_DETAIL\n#if !defined(CL_HPP_USER_OVERRIDE_ERROR_STRINGS)\n#define __GET_DEVICE_INFO_ERR               CL_HPP_ERR_STR_(clGetDeviceInfo)\n#define __GET_PLATFORM_INFO_ERR             CL_HPP_ERR_STR_(clGetPlatformInfo)\n#define __GET_DEVICE_IDS_ERR                CL_HPP_ERR_STR_(clGetDeviceIDs)\n#define __GET_PLATFORM_IDS_ERR              CL_HPP_ERR_STR_(clGetPlatformIDs)\n#define __GET_CONTEXT_INFO_ERR              CL_HPP_ERR_STR_(clGetContextInfo)\n#define __GET_EVENT_INFO_ERR                CL_HPP_ERR_STR_(clGetEventInfo)\n#define __GET_EVENT_PROFILE_INFO_ERR        CL_HPP_ERR_STR_(clGetEventProfileInfo)\n#define __GET_MEM_OBJECT_INFO_ERR           CL_HPP_ERR_STR_(clGetMemObjectInfo)\n#define __GET_IMAGE_INFO_ERR                CL_HPP_ERR_STR_(clGetImageInfo)\n#define __GET_SAMPLER_INFO_ERR              CL_HPP_ERR_STR_(clGetSamplerInfo)\n#define __GET_KERNEL_INFO_ERR               CL_HPP_ERR_STR_(clGetKernelInfo)\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n#define __GET_KERNEL_ARG_INFO_ERR           CL_HPP_ERR_STR_(clGetKernelArgInfo)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n#define __GET_KERNEL_SUB_GROUP_INFO_ERR     CL_HPP_ERR_STR_(clGetKernelSubGroupInfo)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 200\n#define __GET_KERNEL_WORK_GROUP_INFO_ERR    CL_HPP_ERR_STR_(clGetKernelWorkGroupInfo)\n#define __GET_PROGRAM_INFO_ERR              CL_HPP_ERR_STR_(clGetProgramInfo)\n#define __GET_PROGRAM_BUILD_INFO_ERR        CL_HPP_ERR_STR_(clGetProgramBuildInfo)\n#define __GET_COMMAND_QUEUE_INFO_ERR        CL_HPP_ERR_STR_(clGetCommandQueueInfo)\n\n#define __CREATE_CONTEXT_ERR                CL_HPP_ERR_STR_(clCreateContext)\n#define __CREATE_CONTEXT_FROM_TYPE_ERR      CL_HPP_ERR_STR_(clCreateContextFromType)\n#define __GET_SUPPORTED_IMAGE_FORMATS_ERR   CL_HPP_ERR_STR_(clGetSupportedImageFormats)\n\n#define __CREATE_BUFFER_ERR                 CL_HPP_ERR_STR_(clCreateBuffer)\n#define __COPY_ERR                          CL_HPP_ERR_STR_(cl::copy)\n#define __CREATE_SUBBUFFER_ERR              CL_HPP_ERR_STR_(clCreateSubBuffer)\n#define __CREATE_GL_BUFFER_ERR              CL_HPP_ERR_STR_(clCreateFromGLBuffer)\n#define __CREATE_GL_RENDER_BUFFER_ERR       CL_HPP_ERR_STR_(clCreateFromGLBuffer)\n#define __GET_GL_OBJECT_INFO_ERR            CL_HPP_ERR_STR_(clGetGLObjectInfo)\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n#define __CREATE_IMAGE_ERR                  CL_HPP_ERR_STR_(clCreateImage)\n#define __CREATE_GL_TEXTURE_ERR             CL_HPP_ERR_STR_(clCreateFromGLTexture)\n#define __IMAGE_DIMENSION_ERR               CL_HPP_ERR_STR_(Incorrect image dimensions)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n#define __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR CL_HPP_ERR_STR_(clSetMemObjectDestructorCallback)\n\n#define __CREATE_USER_EVENT_ERR             CL_HPP_ERR_STR_(clCreateUserEvent)\n#define __SET_USER_EVENT_STATUS_ERR         CL_HPP_ERR_STR_(clSetUserEventStatus)\n#define __SET_EVENT_CALLBACK_ERR            CL_HPP_ERR_STR_(clSetEventCallback)\n#define __WAIT_FOR_EVENTS_ERR               CL_HPP_ERR_STR_(clWaitForEvents)\n\n#define __CREATE_KERNEL_ERR                 CL_HPP_ERR_STR_(clCreateKernel)\n#define __SET_KERNEL_ARGS_ERR               CL_HPP_ERR_STR_(clSetKernelArg)\n#define __CREATE_PROGRAM_WITH_SOURCE_ERR    CL_HPP_ERR_STR_(clCreateProgramWithSource)\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n#define __CREATE_PROGRAM_WITH_IL_ERR        CL_HPP_ERR_STR_(clCreateProgramWithIL)\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n#define __CREATE_PROGRAM_WITH_BINARY_ERR    CL_HPP_ERR_STR_(clCreateProgramWithBinary)\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210\n#define __CREATE_PROGRAM_WITH_IL_ERR        CL_HPP_ERR_STR_(clCreateProgramWithIL)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 210\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n#define __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR    CL_HPP_ERR_STR_(clCreateProgramWithBuiltInKernels)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n#define __BUILD_PROGRAM_ERR                 CL_HPP_ERR_STR_(clBuildProgram)\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n#define __COMPILE_PROGRAM_ERR               CL_HPP_ERR_STR_(clCompileProgram)\n#define __LINK_PROGRAM_ERR                  CL_HPP_ERR_STR_(clLinkProgram)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n#define __CREATE_KERNELS_IN_PROGRAM_ERR     CL_HPP_ERR_STR_(clCreateKernelsInProgram)\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n#define __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR          CL_HPP_ERR_STR_(clCreateCommandQueueWithProperties)\n#define __CREATE_SAMPLER_WITH_PROPERTIES_ERR                CL_HPP_ERR_STR_(clCreateSamplerWithProperties)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 200\n#define __SET_COMMAND_QUEUE_PROPERTY_ERR    CL_HPP_ERR_STR_(clSetCommandQueueProperty)\n#define __ENQUEUE_READ_BUFFER_ERR           CL_HPP_ERR_STR_(clEnqueueReadBuffer)\n#define __ENQUEUE_READ_BUFFER_RECT_ERR      CL_HPP_ERR_STR_(clEnqueueReadBufferRect)\n#define __ENQUEUE_WRITE_BUFFER_ERR          CL_HPP_ERR_STR_(clEnqueueWriteBuffer)\n#define __ENQUEUE_WRITE_BUFFER_RECT_ERR     CL_HPP_ERR_STR_(clEnqueueWriteBufferRect)\n#define __ENQEUE_COPY_BUFFER_ERR            CL_HPP_ERR_STR_(clEnqueueCopyBuffer)\n#define __ENQEUE_COPY_BUFFER_RECT_ERR       CL_HPP_ERR_STR_(clEnqueueCopyBufferRect)\n#define __ENQUEUE_FILL_BUFFER_ERR           CL_HPP_ERR_STR_(clEnqueueFillBuffer)\n#define __ENQUEUE_READ_IMAGE_ERR            CL_HPP_ERR_STR_(clEnqueueReadImage)\n#define __ENQUEUE_WRITE_IMAGE_ERR           CL_HPP_ERR_STR_(clEnqueueWriteImage)\n#define __ENQUEUE_COPY_IMAGE_ERR            CL_HPP_ERR_STR_(clEnqueueCopyImage)\n#define __ENQUEUE_FILL_IMAGE_ERR            CL_HPP_ERR_STR_(clEnqueueFillImage)\n#define __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR  CL_HPP_ERR_STR_(clEnqueueCopyImageToBuffer)\n#define __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR  CL_HPP_ERR_STR_(clEnqueueCopyBufferToImage)\n#define __ENQUEUE_MAP_BUFFER_ERR            CL_HPP_ERR_STR_(clEnqueueMapBuffer)\n#define __ENQUEUE_MAP_IMAGE_ERR             CL_HPP_ERR_STR_(clEnqueueMapImage)\n#define __ENQUEUE_UNMAP_MEM_OBJECT_ERR      CL_HPP_ERR_STR_(clEnqueueUnMapMemObject)\n#define __ENQUEUE_NDRANGE_KERNEL_ERR        CL_HPP_ERR_STR_(clEnqueueNDRangeKernel)\n#define __ENQUEUE_NATIVE_KERNEL             CL_HPP_ERR_STR_(clEnqueueNativeKernel)\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n#define __ENQUEUE_MIGRATE_MEM_OBJECTS_ERR   CL_HPP_ERR_STR_(clEnqueueMigrateMemObjects)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210\n#define __ENQUEUE_MIGRATE_SVM_ERR   CL_HPP_ERR_STR_(clEnqueueSVMMigrateMem)\n#define __SET_DEFAULT_DEVICE_COMMAND_QUEUE_ERR   CL_HPP_ERR_STR_(clSetDefaultDeviceCommandQueue)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 210\n\n\n#define __ENQUEUE_ACQUIRE_GL_ERR            CL_HPP_ERR_STR_(clEnqueueAcquireGLObjects)\n#define __ENQUEUE_RELEASE_GL_ERR            CL_HPP_ERR_STR_(clEnqueueReleaseGLObjects)\n\n#define __CREATE_PIPE_ERR             CL_HPP_ERR_STR_(clCreatePipe)\n#define __GET_PIPE_INFO_ERR           CL_HPP_ERR_STR_(clGetPipeInfo)\n\n\n#define __RETAIN_ERR                        CL_HPP_ERR_STR_(Retain Object)\n#define __RELEASE_ERR                       CL_HPP_ERR_STR_(Release Object)\n#define __FLUSH_ERR                         CL_HPP_ERR_STR_(clFlush)\n#define __FINISH_ERR                        CL_HPP_ERR_STR_(clFinish)\n#define __VECTOR_CAPACITY_ERR               CL_HPP_ERR_STR_(Vector capacity error)\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210\n#define __GET_HOST_TIMER_ERR           CL_HPP_ERR_STR_(clGetHostTimer)\n#define __GET_DEVICE_AND_HOST_TIMER_ERR           CL_HPP_ERR_STR_(clGetDeviceAndHostTimer)\n#endif\n#if CL_HPP_TARGET_OPENCL_VERSION >= 220\n#define __SET_PROGRAM_RELEASE_CALLBACK_ERR          CL_HPP_ERR_STR_(clSetProgramReleaseCallback)\n#define __SET_PROGRAM_SPECIALIZATION_CONSTANT_ERR   CL_HPP_ERR_STR_(clSetProgramSpecializationConstant)\n#endif\n\n\n/**\n * CL 1.2 version that uses device fission.\n */\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n#define __CREATE_SUB_DEVICES_ERR            CL_HPP_ERR_STR_(clCreateSubDevices)\n#else\n#define __CREATE_SUB_DEVICES_ERR            CL_HPP_ERR_STR_(clCreateSubDevicesEXT)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n\n/**\n * Deprecated APIs for 1.2\n */\n#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS)\n#define __ENQUEUE_MARKER_ERR                CL_HPP_ERR_STR_(clEnqueueMarker)\n#define __ENQUEUE_WAIT_FOR_EVENTS_ERR       CL_HPP_ERR_STR_(clEnqueueWaitForEvents)\n#define __ENQUEUE_BARRIER_ERR               CL_HPP_ERR_STR_(clEnqueueBarrier)\n#define __UNLOAD_COMPILER_ERR               CL_HPP_ERR_STR_(clUnloadCompiler)\n#define __CREATE_GL_TEXTURE_2D_ERR          CL_HPP_ERR_STR_(clCreateFromGLTexture2D)\n#define __CREATE_GL_TEXTURE_3D_ERR          CL_HPP_ERR_STR_(clCreateFromGLTexture3D)\n#define __CREATE_IMAGE2D_ERR                CL_HPP_ERR_STR_(clCreateImage2D)\n#define __CREATE_IMAGE3D_ERR                CL_HPP_ERR_STR_(clCreateImage3D)\n#endif // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS)\n\n/**\n * Deprecated APIs for 2.0\n */\n#if defined(CL_USE_DEPRECATED_OPENCL_1_2_APIS)\n#define __CREATE_COMMAND_QUEUE_ERR          CL_HPP_ERR_STR_(clCreateCommandQueue)\n#define __ENQUEUE_TASK_ERR                  CL_HPP_ERR_STR_(clEnqueueTask)\n#define __CREATE_SAMPLER_ERR                CL_HPP_ERR_STR_(clCreateSampler)\n#endif // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS)\n\n/**\n * CL 1.2 marker and barrier commands\n */\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n#define __ENQUEUE_MARKER_WAIT_LIST_ERR                CL_HPP_ERR_STR_(clEnqueueMarkerWithWaitList)\n#define __ENQUEUE_BARRIER_WAIT_LIST_ERR               CL_HPP_ERR_STR_(clEnqueueBarrierWithWaitList)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210\n#define __CLONE_KERNEL_ERR     CL_HPP_ERR_STR_(clCloneKernel)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 210\n\n#endif // CL_HPP_USER_OVERRIDE_ERROR_STRINGS\n//! \\endcond\n\n\nnamespace detail {\n\n// Generic getInfoHelper. The final parameter is used to guide overload\n// resolution: the actual parameter passed is an int, which makes this\n// a worse conversion sequence than a specialization that declares the\n// parameter as an int.\ntemplate<typename Functor, typename T>\ninline cl_int getInfoHelper(Functor f, cl_uint name, T* param, long)\n{\n    return f(name, sizeof(T), param, NULL);\n}\n\n// Specialized for getInfo<CL_PROGRAM_BINARIES>\n// Assumes that the output vector was correctly resized on the way in\ntemplate <typename Func>\ninline cl_int getInfoHelper(Func f, cl_uint name, vector<vector<unsigned char>>* param, int)\n{\n    if (name != CL_PROGRAM_BINARIES) {\n        return CL_INVALID_VALUE;\n    }\n    if (param) {\n        // Create array of pointers, calculate total size and pass pointer array in\n        size_type numBinaries = param->size();\n        vector<unsigned char*> binariesPointers(numBinaries);\n\n        for (size_type i = 0; i < numBinaries; ++i)\n        {\n            binariesPointers[i] = (*param)[i].data();\n        }\n\n        cl_int err = f(name, numBinaries * sizeof(unsigned char*), binariesPointers.data(), NULL);\n\n        if (err != CL_SUCCESS) {\n            return err;\n        }\n    }\n\n\n    return CL_SUCCESS;\n}\n\n// Specialized getInfoHelper for vector params\ntemplate <typename Func, typename T>\ninline cl_int getInfoHelper(Func f, cl_uint name, vector<T>* param, long)\n{\n    size_type required;\n    cl_int err = f(name, 0, NULL, &required);\n    if (err != CL_SUCCESS) {\n        return err;\n    }\n    const size_type elements = required / sizeof(T);\n\n    // Temporary to avoid changing param on an error\n    vector<T> localData(elements);\n    err = f(name, required, localData.data(), NULL);\n    if (err != CL_SUCCESS) {\n        return err;\n    }\n    if (param) {\n        *param = std::move(localData);\n    }\n\n    return CL_SUCCESS;\n}\n\n/* Specialization for reference-counted types. This depends on the\n * existence of Wrapper<T>::cl_type, and none of the other types having the\n * cl_type member. Note that simplify specifying the parameter as Wrapper<T>\n * does not work, because when using a derived type (e.g. Context) the generic\n * template will provide a better match.\n */\ntemplate <typename Func, typename T>\ninline cl_int getInfoHelper(\n    Func f, cl_uint name, vector<T>* param, int, typename T::cl_type = 0)\n{\n    size_type required;\n    cl_int err = f(name, 0, NULL, &required);\n    if (err != CL_SUCCESS) {\n        return err;\n    }\n\n    const size_type elements = required / sizeof(typename T::cl_type);\n\n    vector<typename T::cl_type> value(elements);\n    err = f(name, required, value.data(), NULL);\n    if (err != CL_SUCCESS) {\n        return err;\n    }\n\n    if (param) {\n        // Assign to convert CL type to T for each element\n        param->resize(elements);\n\n        // Assign to param, constructing with retain behaviour\n        // to correctly capture each underlying CL object\n        for (size_type i = 0; i < elements; i++) {\n            (*param)[i] = T(value[i], true);\n        }\n    }\n    return CL_SUCCESS;\n}\n\n// Specialized GetInfoHelper for string params\ntemplate <typename Func>\ninline cl_int getInfoHelper(Func f, cl_uint name, string* param, long)\n{\n    size_type required;\n    cl_int err = f(name, 0, NULL, &required);\n    if (err != CL_SUCCESS) {\n        return err;\n    }\n\n    // std::string has a constant data member\n    // a char vector does not\n    if (required > 0) {\n        vector<char> value(required);\n        err = f(name, required, value.data(), NULL);\n        if (err != CL_SUCCESS) {\n            return err;\n        }\n        if (param) {\n            param->assign(begin(value), prev(end(value)));\n        }\n    }\n    else if (param) {\n        param->assign(\"\");\n    }\n    return CL_SUCCESS;\n}\n\n// Specialized GetInfoHelper for clsize_t params\ntemplate <typename Func, size_type N>\ninline cl_int getInfoHelper(Func f, cl_uint name, array<size_type, N>* param, long)\n{\n    size_type required;\n    cl_int err = f(name, 0, NULL, &required);\n    if (err != CL_SUCCESS) {\n        return err;\n    }\n\n    size_type elements = required / sizeof(size_type);\n    vector<size_type> value(elements, 0);\n\n    err = f(name, required, value.data(), NULL);\n    if (err != CL_SUCCESS) {\n        return err;\n    }\n    \n    // Bound the copy with N to prevent overruns\n    // if passed N > than the amount copied\n    if (elements > N) {\n        elements = N;\n    }\n    for (size_type i = 0; i < elements; ++i) {\n        (*param)[i] = value[i];\n    }\n\n    return CL_SUCCESS;\n}\n\ntemplate<typename T> struct ReferenceHandler;\n\n/* Specialization for reference-counted types. This depends on the\n * existence of Wrapper<T>::cl_type, and none of the other types having the\n * cl_type member. Note that simplify specifying the parameter as Wrapper<T>\n * does not work, because when using a derived type (e.g. Context) the generic\n * template will provide a better match.\n */\ntemplate<typename Func, typename T>\ninline cl_int getInfoHelper(Func f, cl_uint name, T* param, int, typename T::cl_type = 0)\n{\n    typename T::cl_type value;\n    cl_int err = f(name, sizeof(value), &value, NULL);\n    if (err != CL_SUCCESS) {\n        return err;\n    }\n    *param = value;\n    if (value != NULL)\n    {\n        err = param->retain();\n        if (err != CL_SUCCESS) {\n            return err;\n        }\n    }\n    return CL_SUCCESS;\n}\n\n#define CL_HPP_PARAM_NAME_INFO_1_0_(F) \\\n    F(cl_platform_info, CL_PLATFORM_PROFILE, string) \\\n    F(cl_platform_info, CL_PLATFORM_VERSION, string) \\\n    F(cl_platform_info, CL_PLATFORM_NAME, string) \\\n    F(cl_platform_info, CL_PLATFORM_VENDOR, string) \\\n    F(cl_platform_info, CL_PLATFORM_EXTENSIONS, string) \\\n    \\\n    F(cl_device_info, CL_DEVICE_TYPE, cl_device_type) \\\n    F(cl_device_info, CL_DEVICE_VENDOR_ID, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MAX_COMPUTE_UNITS, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MAX_WORK_GROUP_SIZE, size_type) \\\n    F(cl_device_info, CL_DEVICE_MAX_WORK_ITEM_SIZES, cl::vector<size_type>) \\\n    F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MAX_CLOCK_FREQUENCY, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_ADDRESS_BITS, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MAX_READ_IMAGE_ARGS, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MAX_MEM_ALLOC_SIZE, cl_ulong) \\\n    F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_WIDTH, size_type) \\\n    F(cl_device_info, CL_DEVICE_IMAGE2D_MAX_HEIGHT, size_type) \\\n    F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_WIDTH, size_type) \\\n    F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_HEIGHT, size_type) \\\n    F(cl_device_info, CL_DEVICE_IMAGE3D_MAX_DEPTH, size_type) \\\n    F(cl_device_info, CL_DEVICE_IMAGE_SUPPORT, cl_bool) \\\n    F(cl_device_info, CL_DEVICE_MAX_PARAMETER_SIZE, size_type) \\\n    F(cl_device_info, CL_DEVICE_MAX_SAMPLERS, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MEM_BASE_ADDR_ALIGN, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_SINGLE_FP_CONFIG, cl_device_fp_config) \\\n    F(cl_device_info, CL_DEVICE_DOUBLE_FP_CONFIG, cl_device_fp_config) \\\n    F(cl_device_info, CL_DEVICE_HALF_FP_CONFIG, cl_device_fp_config) \\\n    F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, cl_device_mem_cache_type) \\\n    F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE, cl_uint)\\\n    F(cl_device_info, CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, cl_ulong) \\\n    F(cl_device_info, CL_DEVICE_GLOBAL_MEM_SIZE, cl_ulong) \\\n    F(cl_device_info, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, cl_ulong) \\\n    F(cl_device_info, CL_DEVICE_MAX_CONSTANT_ARGS, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_LOCAL_MEM_TYPE, cl_device_local_mem_type) \\\n    F(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE, cl_ulong) \\\n    F(cl_device_info, CL_DEVICE_ERROR_CORRECTION_SUPPORT, cl_bool) \\\n    F(cl_device_info, CL_DEVICE_PROFILING_TIMER_RESOLUTION, size_type) \\\n    F(cl_device_info, CL_DEVICE_ENDIAN_LITTLE, cl_bool) \\\n    F(cl_device_info, CL_DEVICE_AVAILABLE, cl_bool) \\\n    F(cl_device_info, CL_DEVICE_COMPILER_AVAILABLE, cl_bool) \\\n    F(cl_device_info, CL_DEVICE_EXECUTION_CAPABILITIES, cl_device_exec_capabilities) \\\n    F(cl_device_info, CL_DEVICE_PLATFORM, cl_platform_id) \\\n    F(cl_device_info, CL_DEVICE_NAME, string) \\\n    F(cl_device_info, CL_DEVICE_VENDOR, string) \\\n    F(cl_device_info, CL_DRIVER_VERSION, string) \\\n    F(cl_device_info, CL_DEVICE_PROFILE, string) \\\n    F(cl_device_info, CL_DEVICE_VERSION, string) \\\n    F(cl_device_info, CL_DEVICE_EXTENSIONS, string) \\\n    \\\n    F(cl_context_info, CL_CONTEXT_REFERENCE_COUNT, cl_uint) \\\n    F(cl_context_info, CL_CONTEXT_DEVICES, cl::vector<Device>) \\\n    F(cl_context_info, CL_CONTEXT_PROPERTIES, cl::vector<cl_context_properties>) \\\n    \\\n    F(cl_event_info, CL_EVENT_COMMAND_QUEUE, cl::CommandQueue) \\\n    F(cl_event_info, CL_EVENT_COMMAND_TYPE, cl_command_type) \\\n    F(cl_event_info, CL_EVENT_REFERENCE_COUNT, cl_uint) \\\n    F(cl_event_info, CL_EVENT_COMMAND_EXECUTION_STATUS, cl_int) \\\n    \\\n    F(cl_profiling_info, CL_PROFILING_COMMAND_QUEUED, cl_ulong) \\\n    F(cl_profiling_info, CL_PROFILING_COMMAND_SUBMIT, cl_ulong) \\\n    F(cl_profiling_info, CL_PROFILING_COMMAND_START, cl_ulong) \\\n    F(cl_profiling_info, CL_PROFILING_COMMAND_END, cl_ulong) \\\n    \\\n    F(cl_mem_info, CL_MEM_TYPE, cl_mem_object_type) \\\n    F(cl_mem_info, CL_MEM_FLAGS, cl_mem_flags) \\\n    F(cl_mem_info, CL_MEM_SIZE, size_type) \\\n    F(cl_mem_info, CL_MEM_HOST_PTR, void*) \\\n    F(cl_mem_info, CL_MEM_MAP_COUNT, cl_uint) \\\n    F(cl_mem_info, CL_MEM_REFERENCE_COUNT, cl_uint) \\\n    F(cl_mem_info, CL_MEM_CONTEXT, cl::Context) \\\n    \\\n    F(cl_image_info, CL_IMAGE_FORMAT, cl_image_format) \\\n    F(cl_image_info, CL_IMAGE_ELEMENT_SIZE, size_type) \\\n    F(cl_image_info, CL_IMAGE_ROW_PITCH, size_type) \\\n    F(cl_image_info, CL_IMAGE_SLICE_PITCH, size_type) \\\n    F(cl_image_info, CL_IMAGE_WIDTH, size_type) \\\n    F(cl_image_info, CL_IMAGE_HEIGHT, size_type) \\\n    F(cl_image_info, CL_IMAGE_DEPTH, size_type) \\\n    \\\n    F(cl_sampler_info, CL_SAMPLER_REFERENCE_COUNT, cl_uint) \\\n    F(cl_sampler_info, CL_SAMPLER_CONTEXT, cl::Context) \\\n    F(cl_sampler_info, CL_SAMPLER_NORMALIZED_COORDS, cl_bool) \\\n    F(cl_sampler_info, CL_SAMPLER_ADDRESSING_MODE, cl_addressing_mode) \\\n    F(cl_sampler_info, CL_SAMPLER_FILTER_MODE, cl_filter_mode) \\\n    \\\n    F(cl_program_info, CL_PROGRAM_REFERENCE_COUNT, cl_uint) \\\n    F(cl_program_info, CL_PROGRAM_CONTEXT, cl::Context) \\\n    F(cl_program_info, CL_PROGRAM_NUM_DEVICES, cl_uint) \\\n    F(cl_program_info, CL_PROGRAM_DEVICES, cl::vector<Device>) \\\n    F(cl_program_info, CL_PROGRAM_SOURCE, string) \\\n    F(cl_program_info, CL_PROGRAM_BINARY_SIZES, cl::vector<size_type>) \\\n    F(cl_program_info, CL_PROGRAM_BINARIES, cl::vector<cl::vector<unsigned char>>) \\\n    \\\n    F(cl_program_build_info, CL_PROGRAM_BUILD_STATUS, cl_build_status) \\\n    F(cl_program_build_info, CL_PROGRAM_BUILD_OPTIONS, string) \\\n    F(cl_program_build_info, CL_PROGRAM_BUILD_LOG, string) \\\n    \\\n    F(cl_kernel_info, CL_KERNEL_FUNCTION_NAME, string) \\\n    F(cl_kernel_info, CL_KERNEL_NUM_ARGS, cl_uint) \\\n    F(cl_kernel_info, CL_KERNEL_REFERENCE_COUNT, cl_uint) \\\n    F(cl_kernel_info, CL_KERNEL_CONTEXT, cl::Context) \\\n    F(cl_kernel_info, CL_KERNEL_PROGRAM, cl::Program) \\\n    \\\n    F(cl_kernel_work_group_info, CL_KERNEL_WORK_GROUP_SIZE, size_type) \\\n    F(cl_kernel_work_group_info, CL_KERNEL_COMPILE_WORK_GROUP_SIZE, cl::detail::size_t_array) \\\n    F(cl_kernel_work_group_info, CL_KERNEL_LOCAL_MEM_SIZE, cl_ulong) \\\n    \\\n    F(cl_command_queue_info, CL_QUEUE_CONTEXT, cl::Context) \\\n    F(cl_command_queue_info, CL_QUEUE_DEVICE, cl::Device) \\\n    F(cl_command_queue_info, CL_QUEUE_REFERENCE_COUNT, cl_uint) \\\n    F(cl_command_queue_info, CL_QUEUE_PROPERTIES, cl_command_queue_properties)\n\n\n#define CL_HPP_PARAM_NAME_INFO_1_1_(F) \\\n    F(cl_context_info, CL_CONTEXT_NUM_DEVICES, cl_uint)\\\n    F(cl_device_info, CL_DEVICE_PREFERRED_VECTOR_WIDTH_HALF, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_CHAR, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_SHORT, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_INT, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_LONG, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_FLOAT, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_DOUBLE, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_NATIVE_VECTOR_WIDTH_HALF, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_OPENCL_C_VERSION, string) \\\n    \\\n    F(cl_mem_info, CL_MEM_ASSOCIATED_MEMOBJECT, cl::Memory) \\\n    F(cl_mem_info, CL_MEM_OFFSET, size_type) \\\n    \\\n    F(cl_kernel_work_group_info, CL_KERNEL_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, size_type) \\\n    F(cl_kernel_work_group_info, CL_KERNEL_PRIVATE_MEM_SIZE, cl_ulong) \\\n    \\\n    F(cl_event_info, CL_EVENT_CONTEXT, cl::Context)\n\n#define CL_HPP_PARAM_NAME_INFO_1_2_(F) \\\n    F(cl_program_info, CL_PROGRAM_NUM_KERNELS, size_type) \\\n    F(cl_program_info, CL_PROGRAM_KERNEL_NAMES, string) \\\n    \\\n    F(cl_program_build_info, CL_PROGRAM_BINARY_TYPE, cl_program_binary_type) \\\n    \\\n    F(cl_kernel_info, CL_KERNEL_ATTRIBUTES, string) \\\n    \\\n    F(cl_kernel_arg_info, CL_KERNEL_ARG_ADDRESS_QUALIFIER, cl_kernel_arg_address_qualifier) \\\n    F(cl_kernel_arg_info, CL_KERNEL_ARG_ACCESS_QUALIFIER, cl_kernel_arg_access_qualifier) \\\n    F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_NAME, string) \\\n    F(cl_kernel_arg_info, CL_KERNEL_ARG_NAME, string) \\\n    F(cl_kernel_arg_info, CL_KERNEL_ARG_TYPE_QUALIFIER, cl_kernel_arg_type_qualifier) \\\n    \\\n    F(cl_kernel_work_group_info, CL_KERNEL_GLOBAL_WORK_SIZE, cl::detail::size_t_array) \\\n    \\\n    F(cl_device_info, CL_DEVICE_LINKER_AVAILABLE, cl_bool) \\\n    F(cl_device_info, CL_DEVICE_IMAGE_MAX_BUFFER_SIZE, size_type) \\\n    F(cl_device_info, CL_DEVICE_IMAGE_MAX_ARRAY_SIZE, size_type) \\\n    F(cl_device_info, CL_DEVICE_PARENT_DEVICE, cl::Device) \\\n    F(cl_device_info, CL_DEVICE_PARTITION_MAX_SUB_DEVICES, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_PARTITION_PROPERTIES, cl::vector<cl_device_partition_property>) \\\n    F(cl_device_info, CL_DEVICE_PARTITION_TYPE, cl::vector<cl_device_partition_property>)  \\\n    F(cl_device_info, CL_DEVICE_REFERENCE_COUNT, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_PREFERRED_INTEROP_USER_SYNC, cl_bool) \\\n    F(cl_device_info, CL_DEVICE_PARTITION_AFFINITY_DOMAIN, cl_device_affinity_domain) \\\n    F(cl_device_info, CL_DEVICE_BUILT_IN_KERNELS, string) \\\n    F(cl_device_info, CL_DEVICE_PRINTF_BUFFER_SIZE, size_type) \\\n    \\\n    F(cl_image_info, CL_IMAGE_ARRAY_SIZE, size_type) \\\n    F(cl_image_info, CL_IMAGE_NUM_MIP_LEVELS, cl_uint) \\\n    F(cl_image_info, CL_IMAGE_NUM_SAMPLES, cl_uint)\n\n#define CL_HPP_PARAM_NAME_INFO_2_0_(F) \\\n    F(cl_device_info, CL_DEVICE_QUEUE_ON_HOST_PROPERTIES, cl_command_queue_properties) \\\n    F(cl_device_info, CL_DEVICE_QUEUE_ON_DEVICE_PROPERTIES, cl_command_queue_properties) \\\n    F(cl_device_info, CL_DEVICE_QUEUE_ON_DEVICE_PREFERRED_SIZE, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_QUEUE_ON_DEVICE_MAX_SIZE, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MAX_ON_DEVICE_QUEUES, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MAX_ON_DEVICE_EVENTS, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MAX_PIPE_ARGS, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_PIPE_MAX_ACTIVE_RESERVATIONS, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_PIPE_MAX_PACKET_SIZE, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_SVM_CAPABILITIES, cl_device_svm_capabilities) \\\n    F(cl_device_info, CL_DEVICE_PREFERRED_PLATFORM_ATOMIC_ALIGNMENT, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_PREFERRED_GLOBAL_ATOMIC_ALIGNMENT, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_PREFERRED_LOCAL_ATOMIC_ALIGNMENT, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_IMAGE_PITCH_ALIGNMENT, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_IMAGE_BASE_ADDRESS_ALIGNMENT, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_MAX_READ_WRITE_IMAGE_ARGS, cl_uint ) \\\n    F(cl_device_info, CL_DEVICE_MAX_GLOBAL_VARIABLE_SIZE, size_type ) \\\n    F(cl_device_info, CL_DEVICE_GLOBAL_VARIABLE_PREFERRED_TOTAL_SIZE, size_type ) \\\n    F(cl_profiling_info, CL_PROFILING_COMMAND_COMPLETE, cl_ulong) \\\n    F(cl_kernel_exec_info, CL_KERNEL_EXEC_INFO_SVM_FINE_GRAIN_SYSTEM, cl_bool) \\\n    F(cl_kernel_exec_info, CL_KERNEL_EXEC_INFO_SVM_PTRS, void**) \\\n    F(cl_command_queue_info, CL_QUEUE_SIZE, cl_uint) \\\n    F(cl_mem_info, CL_MEM_USES_SVM_POINTER, cl_bool) \\\n    F(cl_program_build_info, CL_PROGRAM_BUILD_GLOBAL_VARIABLE_TOTAL_SIZE, size_type) \\\n    F(cl_pipe_info, CL_PIPE_PACKET_SIZE, cl_uint) \\\n    F(cl_pipe_info, CL_PIPE_MAX_PACKETS, cl_uint)\n\n#define CL_HPP_PARAM_NAME_INFO_SUBGROUP_KHR_(F) \\\n    F(cl_kernel_sub_group_info, CL_KERNEL_MAX_SUB_GROUP_SIZE_FOR_NDRANGE_KHR, size_type) \\\n    F(cl_kernel_sub_group_info, CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE_KHR, size_type)\n\n#define CL_HPP_PARAM_NAME_INFO_IL_KHR_(F) \\\n    F(cl_device_info, CL_DEVICE_IL_VERSION_KHR, string) \\\n    F(cl_program_info, CL_PROGRAM_IL_KHR, cl::vector<unsigned char>)\n\n#define CL_HPP_PARAM_NAME_INFO_2_1_(F) \\\n    F(cl_platform_info, CL_PLATFORM_HOST_TIMER_RESOLUTION, cl_ulong) \\\n    F(cl_program_info, CL_PROGRAM_IL, cl::vector<unsigned char>) \\\n    F(cl_device_info, CL_DEVICE_MAX_NUM_SUB_GROUPS, cl_uint) \\\n    F(cl_device_info, CL_DEVICE_IL_VERSION, string) \\\n    F(cl_device_info, CL_DEVICE_SUB_GROUP_INDEPENDENT_FORWARD_PROGRESS, cl_bool) \\\n    F(cl_command_queue_info, CL_QUEUE_DEVICE_DEFAULT, cl::DeviceCommandQueue) \\\n    F(cl_kernel_sub_group_info, CL_KERNEL_MAX_SUB_GROUP_SIZE_FOR_NDRANGE, size_type) \\\n    F(cl_kernel_sub_group_info, CL_KERNEL_SUB_GROUP_COUNT_FOR_NDRANGE, size_type) \\\n    F(cl_kernel_sub_group_info, CL_KERNEL_LOCAL_SIZE_FOR_SUB_GROUP_COUNT, cl::detail::size_t_array) \\\n    F(cl_kernel_sub_group_info, CL_KERNEL_MAX_NUM_SUB_GROUPS, size_type) \\\n    F(cl_kernel_sub_group_info, CL_KERNEL_COMPILE_NUM_SUB_GROUPS, size_type)\n\n#define CL_HPP_PARAM_NAME_INFO_2_2_(F) \\\n    F(cl_program_info, CL_PROGRAM_SCOPE_GLOBAL_CTORS_PRESENT, cl_bool) \\\n    F(cl_program_info, CL_PROGRAM_SCOPE_GLOBAL_DTORS_PRESENT, cl_bool)\n\n#define CL_HPP_PARAM_NAME_DEVICE_FISSION_(F) \\\n    F(cl_device_info, CL_DEVICE_PARENT_DEVICE_EXT, cl_device_id) \\\n    F(cl_device_info, CL_DEVICE_PARTITION_TYPES_EXT, cl::vector<cl_device_partition_property_ext>) \\\n    F(cl_device_info, CL_DEVICE_AFFINITY_DOMAINS_EXT, cl::vector<cl_device_partition_property_ext>) \\\n    F(cl_device_info, CL_DEVICE_REFERENCE_COUNT_EXT , cl_uint) \\\n    F(cl_device_info, CL_DEVICE_PARTITION_STYLE_EXT, cl::vector<cl_device_partition_property_ext>)\n\n#define CL_HPP_PARAM_NAME_CL_KHR_EXTENDED_VERSIONING_CL3_SHARED_(F) \\\n    F(cl_platform_info, CL_PLATFORM_NUMERIC_VERSION_KHR, cl_version_khr) \\\n    F(cl_platform_info, CL_PLATFORM_EXTENSIONS_WITH_VERSION_KHR, cl::vector<cl_name_version_khr>) \\\n    \\\n    F(cl_device_info, CL_DEVICE_NUMERIC_VERSION_KHR, cl_version_khr) \\\n    F(cl_device_info, CL_DEVICE_EXTENSIONS_WITH_VERSION_KHR, cl::vector<cl_name_version_khr>) \\\n    F(cl_device_info, CL_DEVICE_ILS_WITH_VERSION_KHR, cl::vector<cl_name_version_khr>) \\\n    F(cl_device_info, CL_DEVICE_BUILT_IN_KERNELS_WITH_VERSION_KHR, cl::vector<cl_name_version_khr>)\n\n#define CL_HPP_PARAM_NAME_CL_KHR_EXTENDED_VERSIONING_KHRONLY_(F) \\\n    F(cl_device_info, CL_DEVICE_OPENCL_C_NUMERIC_VERSION_KHR, cl_version_khr)\n\n#define CL_HPP_PARAM_NAME_INFO_3_0_(F) \\\n    F(cl_platform_info, CL_PLATFORM_NUMERIC_VERSION, cl_version) \\\n    F(cl_platform_info, CL_PLATFORM_EXTENSIONS_WITH_VERSION, cl::vector<cl_name_version>) \\\n    \\\n    F(cl_device_info, CL_DEVICE_NUMERIC_VERSION, cl_version) \\\n    F(cl_device_info, CL_DEVICE_EXTENSIONS_WITH_VERSION, cl::vector<cl_name_version>) \\\n    F(cl_device_info, CL_DEVICE_ILS_WITH_VERSION, cl::vector<cl_name_version>) \\\n    F(cl_device_info, CL_DEVICE_BUILT_IN_KERNELS_WITH_VERSION, cl::vector<cl_name_version>) \\\n    F(cl_device_info, CL_DEVICE_ATOMIC_MEMORY_CAPABILITIES, cl_device_atomic_capabilities) \\\n    F(cl_device_info, CL_DEVICE_ATOMIC_FENCE_CAPABILITIES, cl_device_atomic_capabilities) \\\n    F(cl_device_info, CL_DEVICE_NON_UNIFORM_WORK_GROUP_SUPPORT, cl_bool) \\\n    F(cl_device_info, CL_DEVICE_OPENCL_C_ALL_VERSIONS, cl::vector<cl_name_version>) \\\n    F(cl_device_info, CL_DEVICE_PREFERRED_WORK_GROUP_SIZE_MULTIPLE, size_type) \\\n    F(cl_device_info, CL_DEVICE_WORK_GROUP_COLLECTIVE_FUNCTIONS_SUPPORT, cl_bool) \\\n    F(cl_device_info, CL_DEVICE_GENERIC_ADDRESS_SPACE_SUPPORT, cl_bool) \\\n    F(cl_device_info, CL_DEVICE_OPENCL_C_FEATURES, cl::vector<cl_name_version>) \\\n    F(cl_device_info, CL_DEVICE_DEVICE_ENQUEUE_CAPABILITIES, cl_device_device_enqueue_capabilities) \\\n    F(cl_device_info, CL_DEVICE_PIPE_SUPPORT, cl_bool) \\\n    F(cl_device_info, CL_DEVICE_LATEST_CONFORMANCE_VERSION_PASSED, string) \\\n    \\\n    F(cl_command_queue_info, CL_QUEUE_PROPERTIES_ARRAY, cl::vector<cl_queue_properties>) \\\n    F(cl_mem_info, CL_MEM_PROPERTIES, cl::vector<cl_mem_properties>) \\\n    F(cl_pipe_info, CL_PIPE_PROPERTIES, cl::vector<cl_pipe_properties>) \\\n    F(cl_sampler_info, CL_SAMPLER_PROPERTIES, cl::vector<cl_sampler_properties>)\n\ntemplate <typename enum_type, cl_int Name>\nstruct param_traits {};\n\n#define CL_HPP_DECLARE_PARAM_TRAITS_(token, param_name, T) \\\nstruct token;                                        \\\ntemplate<>                                           \\\nstruct param_traits<detail:: token,param_name>       \\\n{                                                    \\\n    enum { value = param_name };                     \\\n    typedef T param_type;                            \\\n};\n\nCL_HPP_PARAM_NAME_INFO_1_0_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#if CL_HPP_TARGET_OPENCL_VERSION >= 110\nCL_HPP_PARAM_NAME_INFO_1_1_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 110\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\nCL_HPP_PARAM_NAME_INFO_1_2_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\nCL_HPP_PARAM_NAME_INFO_2_0_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 200\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210\nCL_HPP_PARAM_NAME_INFO_2_1_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 210\n#if CL_HPP_TARGET_OPENCL_VERSION >= 220\nCL_HPP_PARAM_NAME_INFO_2_2_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 220\n#if CL_HPP_TARGET_OPENCL_VERSION >= 300\nCL_HPP_PARAM_NAME_INFO_3_0_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 300\n\n#if defined(CL_HPP_USE_CL_SUB_GROUPS_KHR) && CL_HPP_TARGET_OPENCL_VERSION < 210\nCL_HPP_PARAM_NAME_INFO_SUBGROUP_KHR_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // #if defined(CL_HPP_USE_CL_SUB_GROUPS_KHR) && CL_HPP_TARGET_OPENCL_VERSION < 210\n\n#if defined(CL_HPP_USE_IL_KHR)\nCL_HPP_PARAM_NAME_INFO_IL_KHR_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // #if defined(CL_HPP_USE_IL_KHR)\n\n\n// Flags deprecated in OpenCL 2.0\n#define CL_HPP_PARAM_NAME_INFO_1_0_DEPRECATED_IN_2_0_(F) \\\n    F(cl_device_info, CL_DEVICE_QUEUE_PROPERTIES, cl_command_queue_properties)\n\n#define CL_HPP_PARAM_NAME_INFO_1_1_DEPRECATED_IN_2_0_(F) \\\n    F(cl_device_info, CL_DEVICE_HOST_UNIFIED_MEMORY, cl_bool)\n\n#define CL_HPP_PARAM_NAME_INFO_1_2_DEPRECATED_IN_2_0_(F) \\\n    F(cl_image_info, CL_IMAGE_BUFFER, cl::Buffer)\n\n// Include deprecated query flags based on versions\n// Only include deprecated 1.0 flags if 2.0 not active as there is an enum clash\n#if CL_HPP_TARGET_OPENCL_VERSION > 100 && CL_HPP_MINIMUM_OPENCL_VERSION < 200 && CL_HPP_TARGET_OPENCL_VERSION < 200\nCL_HPP_PARAM_NAME_INFO_1_0_DEPRECATED_IN_2_0_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // CL_HPP_MINIMUM_OPENCL_VERSION < 110\n#if CL_HPP_TARGET_OPENCL_VERSION > 110 && CL_HPP_MINIMUM_OPENCL_VERSION < 200\nCL_HPP_PARAM_NAME_INFO_1_1_DEPRECATED_IN_2_0_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // CL_HPP_MINIMUM_OPENCL_VERSION < 120\n#if CL_HPP_TARGET_OPENCL_VERSION > 120 && CL_HPP_MINIMUM_OPENCL_VERSION < 200\nCL_HPP_PARAM_NAME_INFO_1_2_DEPRECATED_IN_2_0_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // CL_HPP_MINIMUM_OPENCL_VERSION < 200\n\n#if defined(CL_HPP_USE_CL_DEVICE_FISSION)\nCL_HPP_PARAM_NAME_DEVICE_FISSION_(CL_HPP_DECLARE_PARAM_TRAITS_);\n#endif // CL_HPP_USE_CL_DEVICE_FISSION\n\n#if defined(cl_khr_extended_versioning)\n#if CL_HPP_TARGET_OPENCL_VERSION < 300\nCL_HPP_PARAM_NAME_CL_KHR_EXTENDED_VERSIONING_CL3_SHARED_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // CL_HPP_TARGET_OPENCL_VERSION < 300\nCL_HPP_PARAM_NAME_CL_KHR_EXTENDED_VERSIONING_KHRONLY_(CL_HPP_DECLARE_PARAM_TRAITS_)\n#endif // cl_khr_extended_versioning\n\n#if defined(cl_khr_device_uuid)\nusing uuid_array = array<cl_uchar, CL_UUID_SIZE_KHR>;\nusing luid_array = array<cl_uchar, CL_LUID_SIZE_KHR>;\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_UUID_KHR, uuid_array)\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DRIVER_UUID_KHR, uuid_array)\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_LUID_VALID_KHR, cl_bool)\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_LUID_KHR, luid_array)\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_NODE_MASK_KHR, cl_uint)\n#endif\n\n#if defined(cl_khr_pci_bus_info)\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_PCI_BUS_INFO_KHR, cl_device_pci_bus_info_khr)\n#endif\n\n#if defined(cl_khr_integer_dot_product)\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_INTEGER_DOT_PRODUCT_CAPABILITIES_KHR, cl_device_integer_dot_product_capabilities_khr)\n#endif\n\n#ifdef CL_PLATFORM_ICD_SUFFIX_KHR\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_platform_info, CL_PLATFORM_ICD_SUFFIX_KHR, string)\n#endif\n\n#ifdef CL_DEVICE_PROFILING_TIMER_OFFSET_AMD\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_PROFILING_TIMER_OFFSET_AMD, cl_ulong)\n#endif\n#ifdef CL_DEVICE_GLOBAL_FREE_MEMORY_AMD\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_GLOBAL_FREE_MEMORY_AMD, vector<size_type>)\n#endif\n#ifdef CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_SIMD_PER_COMPUTE_UNIT_AMD, cl_uint)\n#endif\n#ifdef CL_DEVICE_SIMD_WIDTH_AMD\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_SIMD_WIDTH_AMD, cl_uint)\n#endif\n#ifdef CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_SIMD_INSTRUCTION_WIDTH_AMD, cl_uint)\n#endif\n#ifdef CL_DEVICE_WAVEFRONT_WIDTH_AMD\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_WAVEFRONT_WIDTH_AMD, cl_uint)\n#endif\n#ifdef CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNELS_AMD, cl_uint)\n#endif\n#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANKS_AMD, cl_uint)\n#endif\n#ifdef CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_GLOBAL_MEM_CHANNEL_BANK_WIDTH_AMD, cl_uint)\n#endif\n#ifdef CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_LOCAL_MEM_SIZE_PER_COMPUTE_UNIT_AMD, cl_uint)\n#endif\n#ifdef CL_DEVICE_LOCAL_MEM_BANKS_AMD\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_LOCAL_MEM_BANKS_AMD, cl_uint)\n#endif\n\n#ifdef CL_DEVICE_COMPUTE_UNITS_BITFIELD_ARM\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_COMPUTE_UNITS_BITFIELD_ARM, cl_ulong)\n#endif\n#ifdef CL_DEVICE_JOB_SLOTS_ARM\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_JOB_SLOTS_ARM, cl_uint)\n#endif\n#ifdef CL_DEVICE_SCHEDULING_CONTROLS_CAPABILITIES_ARM\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_SCHEDULING_CONTROLS_CAPABILITIES_ARM, cl_bitfield)\n#endif\n#ifdef CL_KERNEL_EXEC_INFO_WORKGROUP_BATCH_SIZE_ARM\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_kernel_exec_info, CL_KERNEL_EXEC_INFO_WORKGROUP_BATCH_SIZE_ARM, cl_uint)\n#endif\n#ifdef CL_KERNEL_EXEC_INFO_WORKGROUP_BATCH_SIZE_MODIFIER_ARM\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_kernel_exec_info, CL_KERNEL_EXEC_INFO_WORKGROUP_BATCH_SIZE_MODIFIER_ARM, cl_int)\n#endif\n\n#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MAJOR_NV, cl_uint)\n#endif\n#ifdef CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_COMPUTE_CAPABILITY_MINOR_NV, cl_uint)\n#endif\n#ifdef CL_DEVICE_REGISTERS_PER_BLOCK_NV\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_REGISTERS_PER_BLOCK_NV, cl_uint)\n#endif\n#ifdef CL_DEVICE_WARP_SIZE_NV\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_WARP_SIZE_NV, cl_uint)\n#endif\n#ifdef CL_DEVICE_GPU_OVERLAP_NV\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_GPU_OVERLAP_NV, cl_bool)\n#endif\n#ifdef CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_KERNEL_EXEC_TIMEOUT_NV, cl_bool)\n#endif\n#ifdef CL_DEVICE_INTEGRATED_MEMORY_NV\nCL_HPP_DECLARE_PARAM_TRAITS_(cl_device_info, CL_DEVICE_INTEGRATED_MEMORY_NV, cl_bool)\n#endif\n\n// Convenience functions\n\ntemplate <typename Func, typename T>\ninline cl_int\ngetInfo(Func f, cl_uint name, T* param)\n{\n    return getInfoHelper(f, name, param, 0);\n}\n\ntemplate <typename Func, typename Arg0>\nstruct GetInfoFunctor0\n{\n    Func f_; const Arg0& arg0_;\n    cl_int operator ()(\n        cl_uint param, size_type size, void* value, size_type* size_ret)\n    { return f_(arg0_, param, size, value, size_ret); }\n};\n\ntemplate <typename Func, typename Arg0, typename Arg1>\nstruct GetInfoFunctor1\n{\n    Func f_; const Arg0& arg0_; const Arg1& arg1_;\n    cl_int operator ()(\n        cl_uint param, size_type size, void* value, size_type* size_ret)\n    { return f_(arg0_, arg1_, param, size, value, size_ret); }\n};\n\ntemplate <typename Func, typename Arg0, typename T>\ninline cl_int\ngetInfo(Func f, const Arg0& arg0, cl_uint name, T* param)\n{\n    GetInfoFunctor0<Func, Arg0> f0 = { f, arg0 };\n    return getInfoHelper(f0, name, param, 0);\n}\n\ntemplate <typename Func, typename Arg0, typename Arg1, typename T>\ninline cl_int\ngetInfo(Func f, const Arg0& arg0, const Arg1& arg1, cl_uint name, T* param)\n{\n    GetInfoFunctor1<Func, Arg0, Arg1> f0 = { f, arg0, arg1 };\n    return getInfoHelper(f0, name, param, 0);\n}\n\n\ntemplate<typename T>\nstruct ReferenceHandler\n{ };\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n/**\n * OpenCL 1.2 devices do have retain/release.\n */\ntemplate <>\nstruct ReferenceHandler<cl_device_id>\n{\n    /**\n     * Retain the device.\n     * \\param device A valid device created using createSubDevices\n     * \\return \n     *   CL_SUCCESS if the function executed successfully.\n     *   CL_INVALID_DEVICE if device was not a valid subdevice\n     *   CL_OUT_OF_RESOURCES\n     *   CL_OUT_OF_HOST_MEMORY\n     */\n    static cl_int retain(cl_device_id device)\n    { return ::clRetainDevice(device); }\n    /**\n     * Retain the device.\n     * \\param device A valid device created using createSubDevices\n     * \\return \n     *   CL_SUCCESS if the function executed successfully.\n     *   CL_INVALID_DEVICE if device was not a valid subdevice\n     *   CL_OUT_OF_RESOURCES\n     *   CL_OUT_OF_HOST_MEMORY\n     */\n    static cl_int release(cl_device_id device)\n    { return ::clReleaseDevice(device); }\n};\n#else // CL_HPP_TARGET_OPENCL_VERSION >= 120\n/**\n * OpenCL 1.1 devices do not have retain/release.\n */\ntemplate <>\nstruct ReferenceHandler<cl_device_id>\n{\n    // cl_device_id does not have retain().\n    static cl_int retain(cl_device_id)\n    { return CL_SUCCESS; }\n    // cl_device_id does not have release().\n    static cl_int release(cl_device_id)\n    { return CL_SUCCESS; }\n};\n#endif // ! (CL_HPP_TARGET_OPENCL_VERSION >= 120)\n\ntemplate <>\nstruct ReferenceHandler<cl_platform_id>\n{\n    // cl_platform_id does not have retain().\n    static cl_int retain(cl_platform_id)\n    { return CL_SUCCESS; }\n    // cl_platform_id does not have release().\n    static cl_int release(cl_platform_id)\n    { return CL_SUCCESS; }\n};\n\ntemplate <>\nstruct ReferenceHandler<cl_context>\n{\n    static cl_int retain(cl_context context)\n    { return ::clRetainContext(context); }\n    static cl_int release(cl_context context)\n    { return ::clReleaseContext(context); }\n};\n\ntemplate <>\nstruct ReferenceHandler<cl_command_queue>\n{\n    static cl_int retain(cl_command_queue queue)\n    { return ::clRetainCommandQueue(queue); }\n    static cl_int release(cl_command_queue queue)\n    { return ::clReleaseCommandQueue(queue); }\n};\n\ntemplate <>\nstruct ReferenceHandler<cl_mem>\n{\n    static cl_int retain(cl_mem memory)\n    { return ::clRetainMemObject(memory); }\n    static cl_int release(cl_mem memory)\n    { return ::clReleaseMemObject(memory); }\n};\n\ntemplate <>\nstruct ReferenceHandler<cl_sampler>\n{\n    static cl_int retain(cl_sampler sampler)\n    { return ::clRetainSampler(sampler); }\n    static cl_int release(cl_sampler sampler)\n    { return ::clReleaseSampler(sampler); }\n};\n\ntemplate <>\nstruct ReferenceHandler<cl_program>\n{\n    static cl_int retain(cl_program program)\n    { return ::clRetainProgram(program); }\n    static cl_int release(cl_program program)\n    { return ::clReleaseProgram(program); }\n};\n\ntemplate <>\nstruct ReferenceHandler<cl_kernel>\n{\n    static cl_int retain(cl_kernel kernel)\n    { return ::clRetainKernel(kernel); }\n    static cl_int release(cl_kernel kernel)\n    { return ::clReleaseKernel(kernel); }\n};\n\ntemplate <>\nstruct ReferenceHandler<cl_event>\n{\n    static cl_int retain(cl_event event)\n    { return ::clRetainEvent(event); }\n    static cl_int release(cl_event event)\n    { return ::clReleaseEvent(event); }\n};\n\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120 && CL_HPP_MINIMUM_OPENCL_VERSION < 120\n// Extracts version number with major in the upper 16 bits, minor in the lower 16\nstatic cl_uint getVersion(const vector<char> &versionInfo)\n{\n    int highVersion = 0;\n    int lowVersion = 0;\n    int index = 7;\n    while(versionInfo[index] != '.' ) {\n        highVersion *= 10;\n        highVersion += versionInfo[index]-'0';\n        ++index;\n    }\n    ++index;\n    while(versionInfo[index] != ' ' &&  versionInfo[index] != '\\0') {\n        lowVersion *= 10;\n        lowVersion += versionInfo[index]-'0';\n        ++index;\n    }\n    return (highVersion << 16) | lowVersion;\n}\n\nstatic cl_uint getPlatformVersion(cl_platform_id platform)\n{\n    size_type size = 0;\n    clGetPlatformInfo(platform, CL_PLATFORM_VERSION, 0, NULL, &size);\n\n    vector<char> versionInfo(size);\n    clGetPlatformInfo(platform, CL_PLATFORM_VERSION, size, versionInfo.data(), &size);\n    return getVersion(versionInfo);\n}\n\nstatic cl_uint getDevicePlatformVersion(cl_device_id device)\n{\n    cl_platform_id platform;\n    clGetDeviceInfo(device, CL_DEVICE_PLATFORM, sizeof(platform), &platform, NULL);\n    return getPlatformVersion(platform);\n}\n\nstatic cl_uint getContextPlatformVersion(cl_context context)\n{\n    // The platform cannot be queried directly, so we first have to grab a\n    // device and obtain its context\n    size_type size = 0;\n    clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &size);\n    if (size == 0)\n        return 0;\n    vector<cl_device_id> devices(size/sizeof(cl_device_id));\n    clGetContextInfo(context, CL_CONTEXT_DEVICES, size, devices.data(), NULL);\n    return getDevicePlatformVersion(devices[0]);\n}\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120 && CL_HPP_MINIMUM_OPENCL_VERSION < 120\n\ntemplate <typename T>\nclass Wrapper\n{\npublic:\n    typedef T cl_type;\n\nprotected:\n    cl_type object_;\n\npublic:\n    Wrapper() : object_(NULL) { }\n    \n    Wrapper(const cl_type &obj, bool retainObject) : object_(obj) \n    {\n        if (retainObject) { \n            detail::errHandler(retain(), __RETAIN_ERR); \n        }\n    }\n\n    ~Wrapper()\n    {\n        if (object_ != NULL) { release(); }\n    }\n\n    Wrapper(const Wrapper<cl_type>& rhs)\n    {\n        object_ = rhs.object_;\n        detail::errHandler(retain(), __RETAIN_ERR);\n    }\n\n    Wrapper(Wrapper<cl_type>&& rhs) CL_HPP_NOEXCEPT_\n    {\n        object_ = rhs.object_;\n        rhs.object_ = NULL;\n    }\n\n    Wrapper<cl_type>& operator = (const Wrapper<cl_type>& rhs)\n    {\n        if (this != &rhs) {\n            detail::errHandler(release(), __RELEASE_ERR);\n            object_ = rhs.object_;\n            detail::errHandler(retain(), __RETAIN_ERR);\n        }\n        return *this;\n    }\n\n    Wrapper<cl_type>& operator = (Wrapper<cl_type>&& rhs)\n    {\n        if (this != &rhs) {\n            detail::errHandler(release(), __RELEASE_ERR);\n            object_ = rhs.object_;\n            rhs.object_ = NULL;\n        }\n        return *this;\n    }\n\n    Wrapper<cl_type>& operator = (const cl_type &rhs)\n    {\n        detail::errHandler(release(), __RELEASE_ERR);\n        object_ = rhs;\n        return *this;\n    }\n\n    const cl_type& operator ()() const { return object_; }\n\n    cl_type& operator ()() { return object_; }\n\n    cl_type get() const { return object_; }\n\nprotected:\n    template<typename Func, typename U>\n    friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type);\n\n    cl_int retain() const\n    {\n        if (object_ != nullptr) {\n            return ReferenceHandler<cl_type>::retain(object_);\n        }\n        else {\n            return CL_SUCCESS;\n        }\n    }\n\n    cl_int release() const\n    {\n        if (object_ != nullptr) {\n            return ReferenceHandler<cl_type>::release(object_);\n        }\n        else {\n            return CL_SUCCESS;\n        }\n    }\n};\n\ntemplate <>\nclass Wrapper<cl_device_id>\n{\npublic:\n    typedef cl_device_id cl_type;\n\nprotected:\n    cl_type object_;\n    bool referenceCountable_;\n\n    static bool isReferenceCountable(cl_device_id device)\n    {\n        bool retVal = false;\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n#if CL_HPP_MINIMUM_OPENCL_VERSION < 120\n        if (device != NULL) {\n            int version = getDevicePlatformVersion(device);\n            if(version > ((1 << 16) + 1)) {\n                retVal = true;\n            }\n        }\n#else // CL_HPP_MINIMUM_OPENCL_VERSION < 120\n        retVal = true;\n#endif // CL_HPP_MINIMUM_OPENCL_VERSION < 120\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n        return retVal;\n    }\n\npublic:\n    Wrapper() : object_(NULL), referenceCountable_(false) \n    { \n    }\n    \n    Wrapper(const cl_type &obj, bool retainObject) : \n        object_(obj), \n        referenceCountable_(false) \n    {\n        referenceCountable_ = isReferenceCountable(obj); \n\n        if (retainObject) {\n            detail::errHandler(retain(), __RETAIN_ERR);\n        }\n    }\n\n    ~Wrapper()\n    {\n        release();\n    }\n    \n    Wrapper(const Wrapper<cl_type>& rhs)\n    {\n        object_ = rhs.object_;\n        referenceCountable_ = isReferenceCountable(object_); \n        detail::errHandler(retain(), __RETAIN_ERR);\n    }\n\n    Wrapper(Wrapper<cl_type>&& rhs) CL_HPP_NOEXCEPT_\n    {\n        object_ = rhs.object_;\n        referenceCountable_ = rhs.referenceCountable_;\n        rhs.object_ = NULL;\n        rhs.referenceCountable_ = false;\n    }\n\n    Wrapper<cl_type>& operator = (const Wrapper<cl_type>& rhs)\n    {\n        if (this != &rhs) {\n            detail::errHandler(release(), __RELEASE_ERR);\n            object_ = rhs.object_;\n            referenceCountable_ = rhs.referenceCountable_;\n            detail::errHandler(retain(), __RETAIN_ERR);\n        }\n        return *this;\n    }\n\n    Wrapper<cl_type>& operator = (Wrapper<cl_type>&& rhs)\n    {\n        if (this != &rhs) {\n            detail::errHandler(release(), __RELEASE_ERR);\n            object_ = rhs.object_;\n            referenceCountable_ = rhs.referenceCountable_;\n            rhs.object_ = NULL;\n            rhs.referenceCountable_ = false;\n        }\n        return *this;\n    }\n\n    Wrapper<cl_type>& operator = (const cl_type &rhs)\n    {\n        detail::errHandler(release(), __RELEASE_ERR);\n        object_ = rhs;\n        referenceCountable_ = isReferenceCountable(object_); \n        return *this;\n    }\n\n    const cl_type& operator ()() const { return object_; }\n\n    cl_type& operator ()() { return object_; }\n\n    cl_type get() const { return object_; }\n\nprotected:\n    template<typename Func, typename U>\n    friend inline cl_int getInfoHelper(Func, cl_uint, U*, int, typename U::cl_type);\n\n    template<typename Func, typename U>\n    friend inline cl_int getInfoHelper(Func, cl_uint, vector<U>*, int, typename U::cl_type);\n\n    cl_int retain() const\n    {\n        if( object_ != nullptr && referenceCountable_ ) {\n            return ReferenceHandler<cl_type>::retain(object_);\n        }\n        else {\n            return CL_SUCCESS;\n        }\n    }\n\n    cl_int release() const\n    {\n        if (object_ != nullptr && referenceCountable_) {\n            return ReferenceHandler<cl_type>::release(object_);\n        }\n        else {\n            return CL_SUCCESS;\n        }\n    }\n};\n\ntemplate <typename T>\ninline bool operator==(const Wrapper<T> &lhs, const Wrapper<T> &rhs)\n{\n    return lhs() == rhs();\n}\n\ntemplate <typename T>\ninline bool operator!=(const Wrapper<T> &lhs, const Wrapper<T> &rhs)\n{\n    return !operator==(lhs, rhs);\n}\n\n} // namespace detail\n//! \\endcond\n\n\nusing BuildLogType = vector<std::pair<cl::Device, typename detail::param_traits<detail::cl_program_build_info, CL_PROGRAM_BUILD_LOG>::param_type>>;\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n/**\n* Exception class for build errors to carry build info\n*/\nclass BuildError : public Error\n{\nprivate:\n    BuildLogType buildLogs;\npublic:\n    BuildError(cl_int err, const char * errStr, const BuildLogType &vec) : Error(err, errStr), buildLogs(vec)\n    {\n    }\n\n    BuildLogType getBuildLog() const\n    {\n        return buildLogs;\n    }\n};\nnamespace detail {\n    static inline cl_int buildErrHandler(\n        cl_int err,\n        const char * errStr,\n        const BuildLogType &buildLogs)\n    {\n        if (err != CL_SUCCESS) {\n            throw BuildError(err, errStr, buildLogs);\n        }\n        return err;\n    }\n} // namespace detail\n\n#else\nnamespace detail {\n    static inline cl_int buildErrHandler(\n        cl_int err,\n        const char * errStr,\n        const BuildLogType &buildLogs)\n    {\n        (void)buildLogs; // suppress unused variable warning\n        (void)errStr;\n        return err;\n    }\n} // namespace detail\n#endif // #if defined(CL_HPP_ENABLE_EXCEPTIONS)\n\n\n/*! \\stuct ImageFormat\n *  \\brief Adds constructors and member functions for cl_image_format.\n *\n *  \\see cl_image_format\n */\nstruct ImageFormat : public cl_image_format\n{\n    //! \\brief Default constructor - performs no initialization.\n    ImageFormat(){}\n\n    //! \\brief Initializing constructor.\n    ImageFormat(cl_channel_order order, cl_channel_type type)\n    {\n        image_channel_order = order;\n        image_channel_data_type = type;\n    }\n\n    //! \\brief Copy constructor.\n    ImageFormat(const ImageFormat &other) { *this = other; }\n\n    //! \\brief Assignment operator.\n    ImageFormat& operator = (const ImageFormat& rhs)\n    {\n        if (this != &rhs) {\n            this->image_channel_data_type = rhs.image_channel_data_type;\n            this->image_channel_order     = rhs.image_channel_order;\n        }\n        return *this;\n    }\n};\n\n/*! \\brief Class interface for cl_device_id.\n *\n *  \\note Copies of these objects are inexpensive, since they don't 'own'\n *        any underlying resources or data structures.\n *\n *  \\see cl_device_id\n */\nclass Device : public detail::Wrapper<cl_device_id>\n{\nprivate:\n    static std::once_flag default_initialized_;\n    static Device default_;\n    static cl_int default_error_;\n\n    /*! \\brief Create the default context.\n    *\n    * This sets @c default_ and @c default_error_. It does not throw\n    * @c cl::Error.\n    */\n    static void makeDefault();\n\n    /*! \\brief Create the default platform from a provided platform.\n    *\n    * This sets @c default_. It does not throw\n    * @c cl::Error.\n    */\n    static void makeDefaultProvided(const Device &p) {\n        default_ = p;\n    }\n\npublic:\n#ifdef CL_HPP_UNIT_TEST_ENABLE\n    /*! \\brief Reset the default.\n    *\n    * This sets @c default_ to an empty value to support cleanup in\n    * the unit test framework.\n    * This function is not thread safe.\n    */\n    static void unitTestClearDefault() {\n        default_ = Device();\n    }\n#endif // #ifdef CL_HPP_UNIT_TEST_ENABLE\n\n    //! \\brief Default constructor - initializes to NULL.\n    Device() : detail::Wrapper<cl_type>() { }\n\n    /*! \\brief Constructor from cl_device_id.\n     * \n     *  This simply copies the device ID value, which is an inexpensive operation.\n     */\n    explicit Device(const cl_device_id &device, bool retainObject = false) : \n        detail::Wrapper<cl_type>(device, retainObject) { }\n\n    /*! \\brief Returns the first device on the default context.\n     *\n     *  \\see Context::getDefault()\n     */\n    static Device getDefault(\n        cl_int *errResult = NULL)\n    {\n        std::call_once(default_initialized_, makeDefault);\n        detail::errHandler(default_error_);\n        if (errResult != NULL) {\n            *errResult = default_error_;\n        }\n        return default_;\n    }\n\n    /**\n    * Modify the default device to be used by\n    * subsequent operations.\n    * Will only set the default if no default was previously created.\n    * @return updated default device.\n    *         Should be compared to the passed value to ensure that it was updated.\n    */\n    static Device setDefault(const Device &default_device)\n    {\n        std::call_once(default_initialized_, makeDefaultProvided, std::cref(default_device));\n        detail::errHandler(default_error_);\n        return default_;\n    }\n\n    /*! \\brief Assignment operator from cl_device_id.\n     * \n     *  This simply copies the device ID value, which is an inexpensive operation.\n     */\n    Device& operator = (const cl_device_id& rhs)\n    {\n        detail::Wrapper<cl_type>::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n    * Required for MSVC.\n    */\n    Device(const Device& dev) : detail::Wrapper<cl_type>(dev) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n    * Required for MSVC.\n    */\n    Device& operator = (const Device &dev)\n    {\n        detail::Wrapper<cl_type>::operator=(dev);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n    * Required for MSVC.\n    */\n    Device(Device&& dev) CL_HPP_NOEXCEPT_ : detail::Wrapper<cl_type>(std::move(dev)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n    * Required for MSVC.\n    */\n    Device& operator = (Device &&dev)\n    {\n        detail::Wrapper<cl_type>::operator=(std::move(dev));\n        return *this;\n    }\n\n    //! \\brief Wrapper for clGetDeviceInfo().\n    template <typename T>\n    cl_int getInfo(cl_device_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(&::clGetDeviceInfo, object_, name, param),\n            __GET_DEVICE_INFO_ERR);\n    }\n\n    //! \\brief Wrapper for clGetDeviceInfo() that returns by value.\n    template <cl_device_info name> typename\n    detail::param_traits<detail::cl_device_info, name>::param_type\n    getInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_device_info, name>::param_type param;\n        cl_int result = getInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210\n    /**\n     * Return the current value of the host clock as seen by the device.\n     * The resolution of the device timer may be queried with the\n     * CL_DEVICE_PROFILING_TIMER_RESOLUTION query.\n     * @return The host timer value.\n     */\n    cl_ulong getHostTimer(cl_int *error = nullptr)\n    {\n        cl_ulong retVal = 0;\n        cl_int err = \n            clGetHostTimer(this->get(), &retVal);\n        detail::errHandler(\n            err,\n            __GET_HOST_TIMER_ERR);\n        if (error) {\n            *error = err;\n        }\n        return retVal;\n    }\n\n    /**\n     * Return a synchronized pair of host and device timestamps as seen by device.\n     * Use to correlate the clocks and get the host timer only using getHostTimer\n     * as a lower cost mechanism in between calls.\n     * The resolution of the host timer may be queried with the \n     * CL_PLATFORM_HOST_TIMER_RESOLUTION query.\n     * The resolution of the device timer may be queried with the\n     * CL_DEVICE_PROFILING_TIMER_RESOLUTION query.\n     * @return A pair of (device timer, host timer) timer values.\n     */\n    std::pair<cl_ulong, cl_ulong> getDeviceAndHostTimer(cl_int *error = nullptr)\n    {\n        std::pair<cl_ulong, cl_ulong> retVal;\n        cl_int err =\n            clGetDeviceAndHostTimer(this->get(), &(retVal.first), &(retVal.second));\n        detail::errHandler(\n            err,\n            __GET_DEVICE_AND_HOST_TIMER_ERR);\n        if (error) {\n            *error = err;\n        }\n        return retVal;\n    }\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 210\n\n    /**\n     * CL 1.2 version\n     */\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n    //! \\brief Wrapper for clCreateSubDevices().\n    cl_int createSubDevices(\n        const cl_device_partition_property * properties,\n        vector<Device>* devices)\n    {\n        cl_uint n = 0;\n        cl_int err = clCreateSubDevices(object_, properties, 0, NULL, &n);\n        if (err != CL_SUCCESS) {\n            return detail::errHandler(err, __CREATE_SUB_DEVICES_ERR);\n        }\n\n        vector<cl_device_id> ids(n);\n        err = clCreateSubDevices(object_, properties, n, ids.data(), NULL);\n        if (err != CL_SUCCESS) {\n            return detail::errHandler(err, __CREATE_SUB_DEVICES_ERR);\n        }\n\n        // Cannot trivially assign because we need to capture intermediates \n        // with safe construction\n        if (devices) {\n            devices->resize(ids.size());\n\n            // Assign to param, constructing with retain behaviour\n            // to correctly capture each underlying CL object\n            for (size_type i = 0; i < ids.size(); i++) {\n                // We do not need to retain because this device is being created \n                // by the runtime\n                (*devices)[i] = Device(ids[i], false);\n            }\n        }\n\n        return CL_SUCCESS;\n    }\n#elif defined(CL_HPP_USE_CL_DEVICE_FISSION)\n\n/**\n * CL 1.1 version that uses device fission extension.\n */\n    cl_int createSubDevices(\n        const cl_device_partition_property_ext * properties,\n        vector<Device>* devices)\n    {\n        typedef CL_API_ENTRY cl_int \n            ( CL_API_CALL * PFN_clCreateSubDevicesEXT)(\n                cl_device_id /*in_device*/,\n                const cl_device_partition_property_ext * /* properties */,\n                cl_uint /*num_entries*/,\n                cl_device_id * /*out_devices*/,\n                cl_uint * /*num_devices*/ ) CL_API_SUFFIX__VERSION_1_1;\n\n        static PFN_clCreateSubDevicesEXT pfn_clCreateSubDevicesEXT = NULL;\n        CL_HPP_INIT_CL_EXT_FCN_PTR_(clCreateSubDevicesEXT);\n\n        cl_uint n = 0;\n        cl_int err = pfn_clCreateSubDevicesEXT(object_, properties, 0, NULL, &n);\n        if (err != CL_SUCCESS) {\n            return detail::errHandler(err, __CREATE_SUB_DEVICES_ERR);\n        }\n\n        vector<cl_device_id> ids(n);\n        err = pfn_clCreateSubDevicesEXT(object_, properties, n, ids.data(), NULL);\n        if (err != CL_SUCCESS) {\n            return detail::errHandler(err, __CREATE_SUB_DEVICES_ERR);\n        }\n        // Cannot trivially assign because we need to capture intermediates \n        // with safe construction\n        if (devices) {\n            devices->resize(ids.size());\n\n            // Assign to param, constructing with retain behaviour\n            // to correctly capture each underlying CL object\n            for (size_type i = 0; i < ids.size(); i++) {\n                // We do not need to retain because this device is being created \n                // by the runtime\n                (*devices)[i] = Device(ids[i], false);\n            }\n        }\n        return CL_SUCCESS;\n    }\n#endif // defined(CL_HPP_USE_CL_DEVICE_FISSION)\n};\n\nCL_HPP_DEFINE_STATIC_MEMBER_ std::once_flag Device::default_initialized_;\nCL_HPP_DEFINE_STATIC_MEMBER_ Device Device::default_;\nCL_HPP_DEFINE_STATIC_MEMBER_ cl_int Device::default_error_ = CL_SUCCESS;\n\n/*! \\brief Class interface for cl_platform_id.\n *\n *  \\note Copies of these objects are inexpensive, since they don't 'own'\n *        any underlying resources or data structures.\n *\n *  \\see cl_platform_id\n */\nclass Platform : public detail::Wrapper<cl_platform_id>\n{\nprivate:\n    static std::once_flag default_initialized_;\n    static Platform default_;\n    static cl_int default_error_;\n\n    /*! \\brief Create the default context.\n    *\n    * This sets @c default_ and @c default_error_. It does not throw\n    * @c cl::Error.\n    */\n    static void makeDefault() {\n        /* Throwing an exception from a call_once invocation does not do\n        * what we wish, so we catch it and save the error.\n        */\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n        try\n#endif\n        {\n            // If default wasn't passed ,generate one\n            // Otherwise set it\n            cl_uint n = 0;\n\n            cl_int err = ::clGetPlatformIDs(0, NULL, &n);\n            if (err != CL_SUCCESS) {\n                default_error_ = err;\n                return;\n            }\n            if (n == 0) {\n                default_error_ = CL_INVALID_PLATFORM;\n                return;\n            }\n\n            vector<cl_platform_id> ids(n);\n            err = ::clGetPlatformIDs(n, ids.data(), NULL);\n            if (err != CL_SUCCESS) {\n                default_error_ = err;\n                return;\n            }\n\n            default_ = Platform(ids[0]);\n        }\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n        catch (cl::Error &e) {\n            default_error_ = e.err();\n        }\n#endif\n    }\n\n    /*! \\brief Create the default platform from a provided platform.\n     *\n     * This sets @c default_. It does not throw\n     * @c cl::Error.\n     */\n    static void makeDefaultProvided(const Platform &p) {\n       default_ = p;\n    }\n    \npublic:\n#ifdef CL_HPP_UNIT_TEST_ENABLE\n    /*! \\brief Reset the default.\n    *\n    * This sets @c default_ to an empty value to support cleanup in\n    * the unit test framework.\n    * This function is not thread safe.\n    */\n    static void unitTestClearDefault() {\n        default_ = Platform();\n    }\n#endif // #ifdef CL_HPP_UNIT_TEST_ENABLE\n\n    //! \\brief Default constructor - initializes to NULL.\n    Platform() : detail::Wrapper<cl_type>()  { }\n\n    /*! \\brief Constructor from cl_platform_id.\n     * \n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  This simply copies the platform ID value, which is an inexpensive operation.\n     */\n    explicit Platform(const cl_platform_id &platform, bool retainObject = false) : \n        detail::Wrapper<cl_type>(platform, retainObject) { }\n\n    /*! \\brief Assignment operator from cl_platform_id.\n     * \n     *  This simply copies the platform ID value, which is an inexpensive operation.\n     */\n    Platform& operator = (const cl_platform_id& rhs)\n    {\n        detail::Wrapper<cl_type>::operator=(rhs);\n        return *this;\n    }\n\n    static Platform getDefault(\n        cl_int *errResult = NULL)\n    {\n        std::call_once(default_initialized_, makeDefault);\n        detail::errHandler(default_error_);\n        if (errResult != NULL) {\n            *errResult = default_error_;\n        }\n        return default_;\n    }\n\n    /**\n     * Modify the default platform to be used by \n     * subsequent operations.\n     * Will only set the default if no default was previously created.\n     * @return updated default platform. \n     *         Should be compared to the passed value to ensure that it was updated.\n     */\n    static Platform setDefault(const Platform &default_platform)\n    {\n        std::call_once(default_initialized_, makeDefaultProvided, std::cref(default_platform));\n        detail::errHandler(default_error_);\n        return default_;\n    }\n\n    //! \\brief Wrapper for clGetPlatformInfo().\n    template <typename T>\n    cl_int getInfo(cl_platform_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(&::clGetPlatformInfo, object_, name, param),\n            __GET_PLATFORM_INFO_ERR);\n    }\n\n    //! \\brief Wrapper for clGetPlatformInfo() that returns by value.\n    template <cl_platform_info name> typename\n    detail::param_traits<detail::cl_platform_info, name>::param_type\n    getInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_platform_info, name>::param_type param;\n        cl_int result = getInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n\n    /*! \\brief Gets a list of devices for this platform.\n     * \n     *  Wraps clGetDeviceIDs().\n     */\n    cl_int getDevices(\n        cl_device_type type,\n        vector<Device>* devices) const\n    {\n        cl_uint n = 0;\n        if( devices == NULL ) {\n            return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR);\n        }\n        cl_int err = ::clGetDeviceIDs(object_, type, 0, NULL, &n);\n        if (err != CL_SUCCESS  && err != CL_DEVICE_NOT_FOUND) {\n            return detail::errHandler(err, __GET_DEVICE_IDS_ERR);\n        }\n\n        vector<cl_device_id> ids(n);\n        if (n>0) {\n            err = ::clGetDeviceIDs(object_, type, n, ids.data(), NULL);\n            if (err != CL_SUCCESS) {\n                return detail::errHandler(err, __GET_DEVICE_IDS_ERR);\n            }\n        }\n\n        // Cannot trivially assign because we need to capture intermediates \n        // with safe construction\n        // We must retain things we obtain from the API to avoid releasing\n        // API-owned objects.\n        if (devices) {\n            devices->resize(ids.size());\n\n            // Assign to param, constructing with retain behaviour\n            // to correctly capture each underlying CL object\n            for (size_type i = 0; i < ids.size(); i++) {\n                (*devices)[i] = Device(ids[i], true);\n            }\n        }\n        return CL_SUCCESS;\n    }\n\n#if defined(CL_HPP_USE_DX_INTEROP)\n   /*! \\brief Get the list of available D3D10 devices.\n     *\n     *  \\param d3d_device_source.\n     *\n     *  \\param d3d_object.\n     *\n     *  \\param d3d_device_set.\n     *\n     *  \\param devices returns a vector of OpenCL D3D10 devices found. The cl::Device\n     *  values returned in devices can be used to identify a specific OpenCL\n     *  device. If \\a devices argument is NULL, this argument is ignored.\n     *\n     *  \\return One of the following values:\n     *    - CL_SUCCESS if the function is executed successfully.\n     *\n     *  The application can query specific capabilities of the OpenCL device(s)\n     *  returned by cl::getDevices. This can be used by the application to\n     *  determine which device(s) to use.\n     *\n     * \\note In the case that exceptions are enabled and a return value\n     * other than CL_SUCCESS is generated, then cl::Error exception is\n     * generated.\n     */\n    cl_int getDevices(\n        cl_d3d10_device_source_khr d3d_device_source,\n        void *                     d3d_object,\n        cl_d3d10_device_set_khr    d3d_device_set,\n        vector<Device>* devices) const\n    {\n        typedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clGetDeviceIDsFromD3D10KHR)(\n            cl_platform_id platform, \n            cl_d3d10_device_source_khr d3d_device_source, \n            void * d3d_object,\n            cl_d3d10_device_set_khr d3d_device_set,\n            cl_uint num_entries,\n            cl_device_id * devices,\n            cl_uint* num_devices);\n\n        if( devices == NULL ) {\n            return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_DEVICE_IDS_ERR);\n        }\n\n        static PFN_clGetDeviceIDsFromD3D10KHR pfn_clGetDeviceIDsFromD3D10KHR = NULL;\n        CL_HPP_INIT_CL_EXT_FCN_PTR_PLATFORM_(object_, clGetDeviceIDsFromD3D10KHR);\n\n        cl_uint n = 0;\n        cl_int err = pfn_clGetDeviceIDsFromD3D10KHR(\n            object_, \n            d3d_device_source, \n            d3d_object,\n            d3d_device_set, \n            0, \n            NULL, \n            &n);\n        if (err != CL_SUCCESS) {\n            return detail::errHandler(err, __GET_DEVICE_IDS_ERR);\n        }\n\n        vector<cl_device_id> ids(n);\n        err = pfn_clGetDeviceIDsFromD3D10KHR(\n            object_, \n            d3d_device_source, \n            d3d_object,\n            d3d_device_set,\n            n, \n            ids.data(), \n            NULL);\n        if (err != CL_SUCCESS) {\n            return detail::errHandler(err, __GET_DEVICE_IDS_ERR);\n        }\n\n        // Cannot trivially assign because we need to capture intermediates \n        // with safe construction\n        // We must retain things we obtain from the API to avoid releasing\n        // API-owned objects.\n        if (devices) {\n            devices->resize(ids.size());\n\n            // Assign to param, constructing with retain behaviour\n            // to correctly capture each underlying CL object\n            for (size_type i = 0; i < ids.size(); i++) {\n                (*devices)[i] = Device(ids[i], true);\n            }\n        }\n        return CL_SUCCESS;\n    }\n#endif\n\n    /*! \\brief Gets a list of available platforms.\n     * \n     *  Wraps clGetPlatformIDs().\n     */\n    static cl_int get(\n        vector<Platform>* platforms)\n    {\n        cl_uint n = 0;\n\n        if( platforms == NULL ) {\n            return detail::errHandler(CL_INVALID_ARG_VALUE, __GET_PLATFORM_IDS_ERR);\n        }\n\n        cl_int err = ::clGetPlatformIDs(0, NULL, &n);\n        if (err != CL_SUCCESS) {\n            return detail::errHandler(err, __GET_PLATFORM_IDS_ERR);\n        }\n\n        vector<cl_platform_id> ids(n);\n        err = ::clGetPlatformIDs(n, ids.data(), NULL);\n        if (err != CL_SUCCESS) {\n            return detail::errHandler(err, __GET_PLATFORM_IDS_ERR);\n        }\n\n        if (platforms) {\n            platforms->resize(ids.size());\n\n            // Platforms don't reference count\n            for (size_type i = 0; i < ids.size(); i++) {\n                (*platforms)[i] = Platform(ids[i]);\n            }\n        }\n        return CL_SUCCESS;\n    }\n\n    /*! \\brief Gets the first available platform.\n     * \n     *  Wraps clGetPlatformIDs(), returning the first result.\n     */\n    static cl_int get(\n        Platform * platform)\n    {\n        cl_int err;\n        Platform default_platform = Platform::getDefault(&err);\n        if (platform) {\n            *platform = default_platform;\n        }\n        return err;\n    }\n\n    /*! \\brief Gets the first available platform, returning it by value.\n     *\n     * \\return Returns a valid platform if one is available.\n     *         If no platform is available will return a null platform.\n     * Throws an exception if no platforms are available\n     * or an error condition occurs.\n     * Wraps clGetPlatformIDs(), returning the first result.\n     */\n    static Platform get(\n        cl_int * errResult = NULL)\n    {\n        cl_int err;\n        Platform default_platform = Platform::getDefault(&err);\n        if (errResult) {\n            *errResult = err;\n        }\n        return default_platform;\n    }    \n    \n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n    //! \\brief Wrapper for clUnloadCompiler().\n    cl_int\n    unloadCompiler()\n    {\n        return ::clUnloadPlatformCompiler(object_);\n    }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n}; // class Platform\n\nCL_HPP_DEFINE_STATIC_MEMBER_ std::once_flag Platform::default_initialized_;\nCL_HPP_DEFINE_STATIC_MEMBER_ Platform Platform::default_;\nCL_HPP_DEFINE_STATIC_MEMBER_ cl_int Platform::default_error_ = CL_SUCCESS;\n\n\n/**\n * Deprecated APIs for 1.2\n */\n#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS)\n/**\n * Unload the OpenCL compiler.\n * \\note Deprecated for OpenCL 1.2. Use Platform::unloadCompiler instead.\n */\ninline CL_API_PREFIX__VERSION_1_1_DEPRECATED cl_int\nUnloadCompiler() CL_API_SUFFIX__VERSION_1_1_DEPRECATED;\ninline cl_int\nUnloadCompiler()\n{\n    return ::clUnloadCompiler();\n}\n#endif // #if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS)\n\n/*! \\brief Class interface for cl_context.\n *\n *  \\note Copies of these objects are shallow, meaning that the copy will refer\n *        to the same underlying cl_context as the original.  For details, see\n *        clRetainContext() and clReleaseContext().\n *\n *  \\see cl_context\n */\nclass Context \n    : public detail::Wrapper<cl_context>\n{\nprivate:\n    static std::once_flag default_initialized_;\n    static Context default_;\n    static cl_int default_error_;\n\n    /*! \\brief Create the default context from the default device type in the default platform.\n     *\n     * This sets @c default_ and @c default_error_. It does not throw\n     * @c cl::Error.\n     */\n    static void makeDefault() {\n        /* Throwing an exception from a call_once invocation does not do\n         * what we wish, so we catch it and save the error.\n         */\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n        try\n#endif\n        {\n#if !defined(__APPLE__) && !defined(__MACOS)\n            const Platform &p = Platform::getDefault();\n            cl_platform_id defaultPlatform = p();\n            cl_context_properties properties[3] = {\n                CL_CONTEXT_PLATFORM, (cl_context_properties)defaultPlatform, 0\n            };\n#else // #if !defined(__APPLE__) && !defined(__MACOS)\n            cl_context_properties *properties = nullptr;\n#endif // #if !defined(__APPLE__) && !defined(__MACOS)\n\n            default_ = Context(\n                CL_DEVICE_TYPE_DEFAULT,\n                properties,\n                NULL,\n                NULL,\n                &default_error_);\n        }\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n        catch (cl::Error &e) {\n            default_error_ = e.err();\n        }\n#endif\n    }\n\n\n    /*! \\brief Create the default context from a provided Context.\n     *\n     * This sets @c default_. It does not throw\n     * @c cl::Error.\n     */\n    static void makeDefaultProvided(const Context &c) {\n        default_ = c;\n    }\n    \npublic:\n#ifdef CL_HPP_UNIT_TEST_ENABLE\n    /*! \\brief Reset the default.\n    *\n    * This sets @c default_ to an empty value to support cleanup in\n    * the unit test framework.\n    * This function is not thread safe.\n    */\n    static void unitTestClearDefault() {\n        default_ = Context();\n    }\n#endif // #ifdef CL_HPP_UNIT_TEST_ENABLE\n\n    /*! \\brief Constructs a context including a list of specified devices.\n     *\n     *  Wraps clCreateContext().\n     */\n    Context(\n        const vector<Device>& devices,\n        const cl_context_properties* properties = NULL,\n        void (CL_CALLBACK * notifyFptr)(\n            const char *,\n            const void *,\n            size_type,\n            void *) = NULL,\n        void* data = NULL,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        size_type numDevices = devices.size();\n        vector<cl_device_id> deviceIDs(numDevices);\n\n        for( size_type deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) {\n            deviceIDs[deviceIndex] = (devices[deviceIndex])();\n        }\n\n        object_ = ::clCreateContext(\n            properties, (cl_uint) numDevices,\n            deviceIDs.data(),\n            notifyFptr, data, &error);\n\n        detail::errHandler(error, __CREATE_CONTEXT_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    /*! \\brief Constructs a context including a specific device.\n     *\n     *  Wraps clCreateContext().\n     */\n    Context(\n        const Device& device,\n        const cl_context_properties* properties = NULL,\n        void (CL_CALLBACK * notifyFptr)(\n            const char *,\n            const void *,\n            size_type,\n            void *) = NULL,\n        void* data = NULL,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        cl_device_id deviceID = device();\n\n        object_ = ::clCreateContext(\n            properties, 1,\n            &deviceID,\n            notifyFptr, data, &error);\n\n        detail::errHandler(error, __CREATE_CONTEXT_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n    \n    /*! \\brief Constructs a context including all or a subset of devices of a specified type.\n     *\n     *  Wraps clCreateContextFromType().\n     */\n    Context(\n        cl_device_type type,\n        const cl_context_properties* properties = NULL,\n        void (CL_CALLBACK * notifyFptr)(\n            const char *,\n            const void *,\n            size_type,\n            void *) = NULL,\n        void* data = NULL,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n#if !defined(__APPLE__) && !defined(__MACOS)\n        cl_context_properties prop[4] = {CL_CONTEXT_PLATFORM, 0, 0, 0 };\n\n        if (properties == NULL) {\n            // Get a valid platform ID as we cannot send in a blank one\n            vector<Platform> platforms;\n            error = Platform::get(&platforms);\n            if (error != CL_SUCCESS) {\n                detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR);\n                if (err != NULL) {\n                    *err = error;\n                }\n                return;\n            }\n\n            // Check the platforms we found for a device of our specified type\n            cl_context_properties platform_id = 0;\n            for (unsigned int i = 0; i < platforms.size(); i++) {\n\n                vector<Device> devices;\n\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n                try {\n#endif\n\n                    error = platforms[i].getDevices(type, &devices);\n\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n                } catch (cl::Error& e) {\n                    error = e.err();\n                }\n    // Catch if exceptions are enabled as we don't want to exit if first platform has no devices of type\n    // We do error checking next anyway, and can throw there if needed\n#endif\n\n                // Only squash CL_SUCCESS and CL_DEVICE_NOT_FOUND\n                if (error != CL_SUCCESS && error != CL_DEVICE_NOT_FOUND) {\n                    detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR);\n                    if (err != NULL) {\n                        *err = error;\n                    }\n                }\n\n                if (devices.size() > 0) {\n                    platform_id = (cl_context_properties)platforms[i]();\n                    break;\n                }\n            }\n\n            if (platform_id == 0) {\n                detail::errHandler(CL_DEVICE_NOT_FOUND, __CREATE_CONTEXT_FROM_TYPE_ERR);\n                if (err != NULL) {\n                    *err = CL_DEVICE_NOT_FOUND;\n                }\n                return;\n            }\n\n            prop[1] = platform_id;\n            properties = &prop[0];\n        }\n#endif\n        object_ = ::clCreateContextFromType(\n            properties, type, notifyFptr, data, &error);\n\n        detail::errHandler(error, __CREATE_CONTEXT_FROM_TYPE_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Context(const Context& ctx) : detail::Wrapper<cl_type>(ctx) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Context& operator = (const Context &ctx)\n    {\n        detail::Wrapper<cl_type>::operator=(ctx);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Context(Context&& ctx) CL_HPP_NOEXCEPT_ : detail::Wrapper<cl_type>(std::move(ctx)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Context& operator = (Context &&ctx)\n    {\n        detail::Wrapper<cl_type>::operator=(std::move(ctx));\n        return *this;\n    }\n\n\n    /*! \\brief Returns a singleton context including all devices of CL_DEVICE_TYPE_DEFAULT.\n     *\n     *  \\note All calls to this function return the same cl_context as the first.\n     */\n    static Context getDefault(cl_int * err = NULL) \n    {\n        std::call_once(default_initialized_, makeDefault);\n        detail::errHandler(default_error_);\n        if (err != NULL) {\n            *err = default_error_;\n        }\n        return default_;\n    }\n\n    /**\n     * Modify the default context to be used by\n     * subsequent operations.\n     * Will only set the default if no default was previously created.\n     * @return updated default context.\n     *         Should be compared to the passed value to ensure that it was updated.\n     */\n    static Context setDefault(const Context &default_context)\n    {\n        std::call_once(default_initialized_, makeDefaultProvided, std::cref(default_context));\n        detail::errHandler(default_error_);\n        return default_;\n    }\n\n    //! \\brief Default constructor - initializes to NULL.\n    Context() : detail::Wrapper<cl_type>() { }\n\n    /*! \\brief Constructor from cl_context - takes ownership.\n     * \n     *  This effectively transfers ownership of a refcount on the cl_context\n     *  into the new Context object.\n     */\n    explicit Context(const cl_context& context, bool retainObject = false) : \n        detail::Wrapper<cl_type>(context, retainObject) { }\n\n    /*! \\brief Assignment operator from cl_context - takes ownership.\n     * \n     *  This effectively transfers ownership of a refcount on the rhs and calls\n     *  clReleaseContext() on the value previously held by this instance.\n     */\n    Context& operator = (const cl_context& rhs)\n    {\n        detail::Wrapper<cl_type>::operator=(rhs);\n        return *this;\n    }\n\n    //! \\brief Wrapper for clGetContextInfo().\n    template <typename T>\n    cl_int getInfo(cl_context_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(&::clGetContextInfo, object_, name, param),\n            __GET_CONTEXT_INFO_ERR);\n    }\n\n    //! \\brief Wrapper for clGetContextInfo() that returns by value.\n    template <cl_context_info name> typename\n    detail::param_traits<detail::cl_context_info, name>::param_type\n    getInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_context_info, name>::param_type param;\n        cl_int result = getInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n\n    /*! \\brief Gets a list of supported image formats.\n     *  \n     *  Wraps clGetSupportedImageFormats().\n     */\n    cl_int getSupportedImageFormats(\n        cl_mem_flags flags,\n        cl_mem_object_type type,\n        vector<ImageFormat>* formats) const\n    {\n        cl_uint numEntries;\n        \n        if (!formats) {\n            return CL_SUCCESS;\n        }\n\n        cl_int err = ::clGetSupportedImageFormats(\n           object_, \n           flags,\n           type, \n           0, \n           NULL, \n           &numEntries);\n        if (err != CL_SUCCESS) {\n            return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR);\n        }\n\n        if (numEntries > 0) {\n            vector<ImageFormat> value(numEntries);\n            err = ::clGetSupportedImageFormats(\n                object_,\n                flags,\n                type,\n                numEntries,\n                (cl_image_format*)value.data(),\n                NULL);\n            if (err != CL_SUCCESS) {\n                return detail::errHandler(err, __GET_SUPPORTED_IMAGE_FORMATS_ERR);\n            }\n\n            formats->assign(begin(value), end(value));\n        }\n        else {\n            // If no values are being returned, ensure an empty vector comes back\n            formats->clear();\n        }\n\n        return CL_SUCCESS;\n    }\n};\n\ninline void Device::makeDefault()\n{\n    /* Throwing an exception from a call_once invocation does not do\n    * what we wish, so we catch it and save the error.\n    */\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n    try\n#endif\n    {\n        cl_int error = 0;\n\n        Context context = Context::getDefault(&error);\n        detail::errHandler(error, __CREATE_CONTEXT_ERR);\n\n        if (error != CL_SUCCESS) {\n            default_error_ = error;\n        }\n        else {\n            default_ = context.getInfo<CL_CONTEXT_DEVICES>()[0];\n            default_error_ = CL_SUCCESS;\n        }\n    }\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n    catch (cl::Error &e) {\n        default_error_ = e.err();\n    }\n#endif\n}\n\nCL_HPP_DEFINE_STATIC_MEMBER_ std::once_flag Context::default_initialized_;\nCL_HPP_DEFINE_STATIC_MEMBER_ Context Context::default_;\nCL_HPP_DEFINE_STATIC_MEMBER_ cl_int Context::default_error_ = CL_SUCCESS;\n\n/*! \\brief Class interface for cl_event.\n *\n *  \\note Copies of these objects are shallow, meaning that the copy will refer\n *        to the same underlying cl_event as the original.  For details, see\n *        clRetainEvent() and clReleaseEvent().\n *\n *  \\see cl_event\n */\nclass Event : public detail::Wrapper<cl_event>\n{\npublic:\n    //! \\brief Default constructor - initializes to NULL.\n    Event() : detail::Wrapper<cl_type>() { }\n\n    /*! \\brief Constructor from cl_event - takes ownership.\n     * \n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  This effectively transfers ownership of a refcount on the cl_event\n     *  into the new Event object.\n     */\n    explicit Event(const cl_event& event, bool retainObject = false) : \n        detail::Wrapper<cl_type>(event, retainObject) { }\n\n    /*! \\brief Assignment operator from cl_event - takes ownership.\n     *\n     *  This effectively transfers ownership of a refcount on the rhs and calls\n     *  clReleaseEvent() on the value previously held by this instance.\n     */\n    Event& operator = (const cl_event& rhs)\n    {\n        detail::Wrapper<cl_type>::operator=(rhs);\n        return *this;\n    }\n\n    //! \\brief Wrapper for clGetEventInfo().\n    template <typename T>\n    cl_int getInfo(cl_event_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(&::clGetEventInfo, object_, name, param),\n            __GET_EVENT_INFO_ERR);\n    }\n\n    //! \\brief Wrapper for clGetEventInfo() that returns by value.\n    template <cl_event_info name> typename\n    detail::param_traits<detail::cl_event_info, name>::param_type\n    getInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_event_info, name>::param_type param;\n        cl_int result = getInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n\n    //! \\brief Wrapper for clGetEventProfilingInfo().\n    template <typename T>\n    cl_int getProfilingInfo(cl_profiling_info name, T* param) const\n    {\n        return detail::errHandler(detail::getInfo(\n            &::clGetEventProfilingInfo, object_, name, param),\n            __GET_EVENT_PROFILE_INFO_ERR);\n    }\n\n    //! \\brief Wrapper for clGetEventProfilingInfo() that returns by value.\n    template <cl_profiling_info name> typename\n    detail::param_traits<detail::cl_profiling_info, name>::param_type\n    getProfilingInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_profiling_info, name>::param_type param;\n        cl_int result = getProfilingInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n\n    /*! \\brief Blocks the calling thread until this event completes.\n     * \n     *  Wraps clWaitForEvents().\n     */\n    cl_int wait() const\n    {\n        return detail::errHandler(\n            ::clWaitForEvents(1, &object_),\n            __WAIT_FOR_EVENTS_ERR);\n    }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 110\n    /*! \\brief Registers a user callback function for a specific command execution status.\n     *\n     *  Wraps clSetEventCallback().\n     */\n    cl_int setCallback(\n        cl_int type,\n        void (CL_CALLBACK * pfn_notify)(cl_event, cl_int, void *),\n        void * user_data = NULL)\n    {\n        return detail::errHandler(\n            ::clSetEventCallback(\n                object_,\n                type,\n                pfn_notify,\n                user_data), \n            __SET_EVENT_CALLBACK_ERR);\n    }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 110\n\n    /*! \\brief Blocks the calling thread until every event specified is complete.\n     * \n     *  Wraps clWaitForEvents().\n     */\n    static cl_int\n    waitForEvents(const vector<Event>& events)\n    {\n        return detail::errHandler(\n            ::clWaitForEvents(\n                (cl_uint) events.size(), (events.size() > 0) ? (cl_event*)&events.front() : NULL),\n            __WAIT_FOR_EVENTS_ERR);\n    }\n};\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 110\n/*! \\brief Class interface for user events (a subset of cl_event's).\n * \n *  See Event for details about copy semantics, etc.\n */\nclass UserEvent : public Event\n{\npublic:\n    /*! \\brief Constructs a user event on a given context.\n     *\n     *  Wraps clCreateUserEvent().\n     */\n    UserEvent(\n        const Context& context,\n        cl_int * err = NULL)\n    {\n        cl_int error;\n        object_ = ::clCreateUserEvent(\n            context(),\n            &error);\n\n        detail::errHandler(error, __CREATE_USER_EVENT_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    //! \\brief Default constructor - initializes to NULL.\n    UserEvent() : Event() { }\n\n    /*! \\brief Sets the execution status of a user event object.\n     *\n     *  Wraps clSetUserEventStatus().\n     */\n    cl_int setStatus(cl_int status)\n    {\n        return detail::errHandler(\n            ::clSetUserEventStatus(object_,status), \n            __SET_USER_EVENT_STATUS_ERR);\n    }\n};\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 110\n\n/*! \\brief Blocks the calling thread until every event specified is complete.\n * \n *  Wraps clWaitForEvents().\n */\ninline static cl_int\nWaitForEvents(const vector<Event>& events)\n{\n    return detail::errHandler(\n        ::clWaitForEvents(\n            (cl_uint) events.size(), (events.size() > 0) ? (cl_event*)&events.front() : NULL),\n        __WAIT_FOR_EVENTS_ERR);\n}\n\n/*! \\brief Class interface for cl_mem.\n *\n *  \\note Copies of these objects are shallow, meaning that the copy will refer\n *        to the same underlying cl_mem as the original.  For details, see\n *        clRetainMemObject() and clReleaseMemObject().\n *\n *  \\see cl_mem\n */\nclass Memory : public detail::Wrapper<cl_mem>\n{\npublic:\n    //! \\brief Default constructor - initializes to NULL.\n    Memory() : detail::Wrapper<cl_type>() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     *  Optionally transfer ownership of a refcount on the cl_mem\n     *  into the new Memory object.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *\n     *  See Memory for further details.\n     */\n    explicit Memory(const cl_mem& memory, bool retainObject) :\n        detail::Wrapper<cl_type>(memory, retainObject) { }\n\n    /*! \\brief Assignment operator from cl_mem - takes ownership.\n     *\n     *  This effectively transfers ownership of a refcount on the rhs and calls\n     *  clReleaseMemObject() on the value previously held by this instance.\n     */\n    Memory& operator = (const cl_mem& rhs)\n    {\n        detail::Wrapper<cl_type>::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Memory(const Memory& mem) : detail::Wrapper<cl_type>(mem) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Memory& operator = (const Memory &mem)\n    {\n        detail::Wrapper<cl_type>::operator=(mem);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Memory(Memory&& mem) CL_HPP_NOEXCEPT_ : detail::Wrapper<cl_type>(std::move(mem)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Memory& operator = (Memory &&mem)\n    {\n        detail::Wrapper<cl_type>::operator=(std::move(mem));\n        return *this;\n    }\n\n\n    //! \\brief Wrapper for clGetMemObjectInfo().\n    template <typename T>\n    cl_int getInfo(cl_mem_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(&::clGetMemObjectInfo, object_, name, param),\n            __GET_MEM_OBJECT_INFO_ERR);\n    }\n\n    //! \\brief Wrapper for clGetMemObjectInfo() that returns by value.\n    template <cl_mem_info name> typename\n    detail::param_traits<detail::cl_mem_info, name>::param_type\n    getInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_mem_info, name>::param_type param;\n        cl_int result = getInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 110\n    /*! \\brief Registers a callback function to be called when the memory object\n     *         is no longer needed.\n     *\n     *  Wraps clSetMemObjectDestructorCallback().\n     *\n     *  Repeated calls to this function, for a given cl_mem value, will append\n     *  to the list of functions called (in reverse order) when memory object's\n     *  resources are freed and the memory object is deleted.\n     *\n     *  \\note\n     *  The registered callbacks are associated with the underlying cl_mem\n     *  value - not the Memory class instance.\n     */\n    cl_int setDestructorCallback(\n        void (CL_CALLBACK * pfn_notify)(cl_mem, void *),\n        void * user_data = NULL)\n    {\n        return detail::errHandler(\n            ::clSetMemObjectDestructorCallback(\n                object_,\n                pfn_notify,\n                user_data), \n            __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR);\n    }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 110\n\n};\n\n// Pre-declare copy functions\nclass Buffer;\ntemplate< typename IteratorType >\ncl_int copy( IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer );\ntemplate< typename IteratorType >\ncl_int copy( const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator );\ntemplate< typename IteratorType >\ncl_int copy( const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer );\ntemplate< typename IteratorType >\ncl_int copy( const CommandQueue &queue, const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator );\n\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\nnamespace detail\n{\n    class SVMTraitNull\n    {\n    public:\n        static cl_svm_mem_flags getSVMMemFlags()\n        {\n            return 0;\n        }\n    };\n} // namespace detail\n\ntemplate<class Trait = detail::SVMTraitNull>\nclass SVMTraitReadWrite\n{\npublic:\n    static cl_svm_mem_flags getSVMMemFlags()\n    {\n        return CL_MEM_READ_WRITE |\n            Trait::getSVMMemFlags();\n    }\n};\n\ntemplate<class Trait = detail::SVMTraitNull>\nclass SVMTraitReadOnly\n{\npublic:\n    static cl_svm_mem_flags getSVMMemFlags()\n    {\n        return CL_MEM_READ_ONLY |\n            Trait::getSVMMemFlags();\n    }\n};\n\ntemplate<class Trait = detail::SVMTraitNull>\nclass SVMTraitWriteOnly\n{\npublic:\n    static cl_svm_mem_flags getSVMMemFlags()\n    {\n        return CL_MEM_WRITE_ONLY |\n            Trait::getSVMMemFlags();\n    }\n};\n\ntemplate<class Trait = SVMTraitReadWrite<>>\nclass SVMTraitCoarse\n{\npublic:\n    static cl_svm_mem_flags getSVMMemFlags()\n    {\n        return Trait::getSVMMemFlags();\n    }\n};\n\ntemplate<class Trait = SVMTraitReadWrite<>>\nclass SVMTraitFine\n{\npublic:\n    static cl_svm_mem_flags getSVMMemFlags()\n    {\n        return CL_MEM_SVM_FINE_GRAIN_BUFFER |\n            Trait::getSVMMemFlags();\n    }\n};\n\ntemplate<class Trait = SVMTraitReadWrite<>>\nclass SVMTraitAtomic\n{\npublic:\n    static cl_svm_mem_flags getSVMMemFlags()\n    {\n        return\n            CL_MEM_SVM_FINE_GRAIN_BUFFER |\n            CL_MEM_SVM_ATOMICS |\n            Trait::getSVMMemFlags();\n    }\n};\n\n// Pre-declare SVM map function\ntemplate<typename T>\ninline cl_int enqueueMapSVM(\n    T* ptr,\n    cl_bool blocking,\n    cl_map_flags flags,\n    size_type size,\n    const vector<Event>* events = NULL,\n    Event* event = NULL);\n\n/**\n * STL-like allocator class for managing SVM objects provided for convenience.\n *\n * Note that while this behaves like an allocator for the purposes of constructing vectors and similar objects,\n * care must be taken when using with smart pointers.\n * The allocator should not be used to construct a unique_ptr if we are using coarse-grained SVM mode because\n * the coarse-grained management behaviour would behave incorrectly with respect to reference counting.\n *\n * Instead the allocator embeds a Deleter which may be used with unique_ptr and is used\n * with the allocate_shared and allocate_ptr supplied operations.\n */\ntemplate<typename T, class SVMTrait>\nclass SVMAllocator {\nprivate:\n    Context context_;\n\npublic:\n    typedef T value_type;\n    typedef value_type* pointer;\n    typedef const value_type* const_pointer;\n    typedef value_type& reference;\n    typedef const value_type& const_reference;\n    typedef std::size_t size_type;\n    typedef std::ptrdiff_t difference_type;\n\n    template<typename U>\n    struct rebind\n    {\n        typedef SVMAllocator<U, SVMTrait> other;\n    };\n\n    template<typename U, typename V>\n    friend class SVMAllocator;\n\n    SVMAllocator() :\n        context_(Context::getDefault())\n    {\n    }\n\n    explicit SVMAllocator(cl::Context context) :\n        context_(context)\n    {\n    }\n\n\n    SVMAllocator(const SVMAllocator &other) :\n        context_(other.context_)\n    {\n    }\n\n    template<typename U>\n    SVMAllocator(const SVMAllocator<U, SVMTrait> &other) :\n        context_(other.context_)\n    {\n    }\n\n    ~SVMAllocator()\n    {\n    }\n\n    pointer address(reference r) CL_HPP_NOEXCEPT_\n    {\n        return std::addressof(r);\n    }\n\n    const_pointer address(const_reference r) CL_HPP_NOEXCEPT_\n    {\n        return std::addressof(r);\n    }\n\n    /**\n     * Allocate an SVM pointer.\n     *\n     * If the allocator is coarse-grained, this will take ownership to allow\n     * containers to correctly construct data in place. \n     */\n    pointer allocate(\n        size_type size,\n        typename cl::SVMAllocator<void, SVMTrait>::const_pointer = 0)\n    {\n        // Allocate memory with default alignment matching the size of the type\n        void* voidPointer =\n            clSVMAlloc(\n            context_(),\n            SVMTrait::getSVMMemFlags(),\n            size*sizeof(T),\n            0);\n        pointer retValue = reinterpret_cast<pointer>(\n            voidPointer);\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n        if (!retValue) {\n            std::bad_alloc excep;\n            throw excep;\n        }\n#endif // #if defined(CL_HPP_ENABLE_EXCEPTIONS)\n\n        // If allocation was coarse-grained then map it\n        if (!(SVMTrait::getSVMMemFlags() & CL_MEM_SVM_FINE_GRAIN_BUFFER)) {\n            cl_int err = enqueueMapSVM(retValue, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE, size*sizeof(T));\n            if (err != CL_SUCCESS) {\n                std::bad_alloc excep;\n                throw excep;\n            }\n        }\n\n        // If exceptions disabled, return null pointer from allocator\n        return retValue;\n    }\n\n    void deallocate(pointer p, size_type)\n    {\n        clSVMFree(context_(), p);\n    }\n\n    /**\n     * Return the maximum possible allocation size.\n     * This is the minimum of the maximum sizes of all devices in the context.\n     */\n    size_type max_size() const CL_HPP_NOEXCEPT_\n    {\n        size_type maxSize = std::numeric_limits<size_type>::max() / sizeof(T);\n\n        for (const Device &d : context_.getInfo<CL_CONTEXT_DEVICES>()) {\n            maxSize = std::min(\n                maxSize, \n                static_cast<size_type>(d.getInfo<CL_DEVICE_MAX_MEM_ALLOC_SIZE>()));\n        }\n\n        return maxSize;\n    }\n\n    template< class U, class... Args >\n    void construct(U* p, Args&&... args)\n    {\n        new(p)T(args...);\n    }\n\n    template< class U >\n    void destroy(U* p)\n    {\n        p->~U();\n    }\n\n    /**\n     * Returns true if the contexts match.\n     */\n    inline bool operator==(SVMAllocator const& rhs)\n    {\n        return (context_==rhs.context_);\n    }\n\n    inline bool operator!=(SVMAllocator const& a)\n    {\n        return !operator==(a);\n    }\n}; // class SVMAllocator        return cl::pointer<T>(tmp, detail::Deleter<T, Alloc>{alloc, copies});\n\n\ntemplate<class SVMTrait>\nclass SVMAllocator<void, SVMTrait> {\npublic:\n    typedef void value_type;\n    typedef value_type* pointer;\n    typedef const value_type* const_pointer;\n\n    template<typename U>\n    struct rebind\n    {\n        typedef SVMAllocator<U, SVMTrait> other;\n    };\n\n    template<typename U, typename V>\n    friend class SVMAllocator;\n};\n\n#if !defined(CL_HPP_NO_STD_UNIQUE_PTR)\nnamespace detail\n{\n    template<class Alloc>\n    class Deleter {\n    private:\n        Alloc alloc_;\n        size_type copies_;\n\n    public:\n        typedef typename std::allocator_traits<Alloc>::pointer pointer;\n\n        Deleter(const Alloc &alloc, size_type copies) : alloc_{ alloc }, copies_{ copies }\n        {\n        }\n\n        void operator()(pointer ptr) const {\n            Alloc tmpAlloc{ alloc_ };\n            std::allocator_traits<Alloc>::destroy(tmpAlloc, std::addressof(*ptr));\n            std::allocator_traits<Alloc>::deallocate(tmpAlloc, ptr, copies_);\n        }\n    };\n} // namespace detail\n\n/**\n * Allocation operation compatible with std::allocate_ptr.\n * Creates a unique_ptr<T> by default.\n * This requirement is to ensure that the control block is not\n * allocated in memory inaccessible to the host.\n */\ntemplate <class T, class Alloc, class... Args>\ncl::pointer<T, detail::Deleter<Alloc>> allocate_pointer(const Alloc &alloc_, Args&&... args)\n{\n    Alloc alloc(alloc_);\n    static const size_type copies = 1;\n\n    // Ensure that creation of the management block and the\n    // object are dealt with separately such that we only provide a deleter\n\n    T* tmp = std::allocator_traits<Alloc>::allocate(alloc, copies);\n    if (!tmp) {\n        std::bad_alloc excep;\n        throw excep;\n    }\n    try {\n        std::allocator_traits<Alloc>::construct(\n            alloc,\n            std::addressof(*tmp),\n            std::forward<Args>(args)...);\n\n        return cl::pointer<T, detail::Deleter<Alloc>>(tmp, detail::Deleter<Alloc>{alloc, copies});\n    }\n    catch (std::bad_alloc& b)\n    {\n        std::allocator_traits<Alloc>::deallocate(alloc, tmp, copies);\n        throw;\n    }\n}\n\ntemplate< class T, class SVMTrait, class... Args >\ncl::pointer<T, detail::Deleter<SVMAllocator<T, SVMTrait>>> allocate_svm(Args... args)\n{\n    SVMAllocator<T, SVMTrait> alloc;\n    return cl::allocate_pointer<T>(alloc, args...);\n}\n\ntemplate< class T, class SVMTrait, class... Args >\ncl::pointer<T, detail::Deleter<SVMAllocator<T, SVMTrait>>> allocate_svm(const cl::Context &c, Args... args)\n{\n    SVMAllocator<T, SVMTrait> alloc(c);\n    return cl::allocate_pointer<T>(alloc, args...);\n}\n#endif // #if !defined(CL_HPP_NO_STD_UNIQUE_PTR)\n\n/*! \\brief Vector alias to simplify contruction of coarse-grained SVM containers.\n * \n */\ntemplate < class T >\nusing coarse_svm_vector = vector<T, cl::SVMAllocator<int, cl::SVMTraitCoarse<>>>;\n\n/*! \\brief Vector alias to simplify contruction of fine-grained SVM containers.\n*\n*/\ntemplate < class T >\nusing fine_svm_vector = vector<T, cl::SVMAllocator<int, cl::SVMTraitFine<>>>;\n\n/*! \\brief Vector alias to simplify contruction of fine-grained SVM containers that support platform atomics.\n*\n*/\ntemplate < class T >\nusing atomic_svm_vector = vector<T, cl::SVMAllocator<int, cl::SVMTraitAtomic<>>>;\n\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\n\n/*! \\brief Class interface for Buffer Memory Objects.\n * \n *  See Memory for details about copy semantics, etc.\n *\n *  \\see Memory\n */\nclass Buffer : public Memory\n{\npublic:\n\n    /*! \\brief Constructs a Buffer in a specified context.\n     *\n     *  Wraps clCreateBuffer().\n     *\n     *  \\param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was\n     *                  specified.  Note alignment & exclusivity requirements.\n     */\n    Buffer(\n        const Context& context,\n        cl_mem_flags flags,\n        size_type size,\n        void* host_ptr = NULL,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n        object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error);\n\n        detail::errHandler(error, __CREATE_BUFFER_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    /*! \\brief Constructs a Buffer in the default context.\n     *\n     *  Wraps clCreateBuffer().\n     *\n     *  \\param host_ptr Storage to be used if the CL_MEM_USE_HOST_PTR flag was\n     *                  specified.  Note alignment & exclusivity requirements.\n     *\n     *  \\see Context::getDefault()\n     */\n    Buffer(\n         cl_mem_flags flags,\n        size_type size,\n        void* host_ptr = NULL,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        Context context = Context::getDefault(err);\n\n        object_ = ::clCreateBuffer(context(), flags, size, host_ptr, &error);\n\n        detail::errHandler(error, __CREATE_BUFFER_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    /*!\n     * \\brief Construct a Buffer from a host container via iterators.\n     * IteratorType must be random access.\n     * If useHostPtr is specified iterators must represent contiguous data.\n     */\n    template< typename IteratorType >\n    Buffer(\n        IteratorType startIterator,\n        IteratorType endIterator,\n        bool readOnly,\n        bool useHostPtr = false,\n        cl_int* err = NULL)\n    {\n        typedef typename std::iterator_traits<IteratorType>::value_type DataType;\n        cl_int error;\n\n        cl_mem_flags flags = 0;\n        if( readOnly ) {\n            flags |= CL_MEM_READ_ONLY;\n        }\n        else {\n            flags |= CL_MEM_READ_WRITE;\n        }\n        if( useHostPtr ) {\n            flags |= CL_MEM_USE_HOST_PTR;\n        }\n        \n        size_type size = sizeof(DataType)*(endIterator - startIterator);\n\n        Context context = Context::getDefault(err);\n\n        if( useHostPtr ) {\n            object_ = ::clCreateBuffer(context(), flags, size, static_cast<DataType*>(&*startIterator), &error);\n        } else {\n            object_ = ::clCreateBuffer(context(), flags, size, 0, &error);\n        }\n\n        detail::errHandler(error, __CREATE_BUFFER_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n\n        if( !useHostPtr ) {\n            error = cl::copy(startIterator, endIterator, *this);\n            detail::errHandler(error, __CREATE_BUFFER_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n    }\n\n    /*!\n     * \\brief Construct a Buffer from a host container via iterators using a specified context.\n     * IteratorType must be random access.\n     * If useHostPtr is specified iterators must represent contiguous data.\n     */\n    template< typename IteratorType >\n    Buffer(const Context &context, IteratorType startIterator, IteratorType endIterator,\n        bool readOnly, bool useHostPtr = false, cl_int* err = NULL);\n    \n    /*!\n    * \\brief Construct a Buffer from a host container via iterators using a specified queue.\n    * If useHostPtr is specified iterators must be random access.\n    */\n    template< typename IteratorType >\n    Buffer(const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator,\n        bool readOnly, bool useHostPtr = false, cl_int* err = NULL);\n\n    //! \\brief Default constructor - initializes to NULL.\n    Buffer() : Memory() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with earlier versions.\n     *\n     *  See Memory for further details.\n     */\n    explicit Buffer(const cl_mem& buffer, bool retainObject = false) :\n        Memory(buffer, retainObject) { }\n\n    /*! \\brief Assignment from cl_mem - performs shallow copy.\n    *\n    *  See Memory for further details.\n    */\n    Buffer& operator = (const cl_mem& rhs)\n    {\n        Memory::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Buffer(const Buffer& buf) : Memory(buf) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Buffer& operator = (const Buffer &buf)\n    {\n        Memory::operator=(buf);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Buffer(Buffer&& buf) CL_HPP_NOEXCEPT_ : Memory(std::move(buf)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Buffer& operator = (Buffer &&buf)\n    {\n        Memory::operator=(std::move(buf));\n        return *this;\n    }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 110\n    /*! \\brief Creates a new buffer object from this.\n     *\n     *  Wraps clCreateSubBuffer().\n     */\n    Buffer createSubBuffer(\n        cl_mem_flags flags,\n        cl_buffer_create_type buffer_create_type,\n        const void * buffer_create_info,\n        cl_int * err = NULL)\n    {\n        Buffer result;\n        cl_int error;\n        result.object_ = ::clCreateSubBuffer(\n            object_, \n            flags, \n            buffer_create_type, \n            buffer_create_info, \n            &error);\n\n        detail::errHandler(error, __CREATE_SUBBUFFER_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n\n        return result;\n    }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 110\n};\n\n#if defined (CL_HPP_USE_DX_INTEROP)\n/*! \\brief Class interface for creating OpenCL buffers from ID3D10Buffer's.\n *\n *  This is provided to facilitate interoperability with Direct3D.\n * \n *  See Memory for details about copy semantics, etc.\n *\n *  \\see Memory\n */\nclass BufferD3D10 : public Buffer\n{\npublic:\n   \n\n    /*! \\brief Constructs a BufferD3D10, in a specified context, from a\n     *         given ID3D10Buffer.\n     *\n     *  Wraps clCreateFromD3D10BufferKHR().\n     */\n    BufferD3D10(\n        const Context& context,\n        cl_mem_flags flags,\n        ID3D10Buffer* bufobj,\n        cl_int * err = NULL) : pfn_clCreateFromD3D10BufferKHR(nullptr)\n    {\n        typedef CL_API_ENTRY cl_mem (CL_API_CALL *PFN_clCreateFromD3D10BufferKHR)(\n            cl_context context, cl_mem_flags flags, ID3D10Buffer*  buffer,\n            cl_int* errcode_ret);\n        PFN_clCreateFromD3D10BufferKHR pfn_clCreateFromD3D10BufferKHR;\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n        vector<cl_context_properties> props = context.getInfo<CL_CONTEXT_PROPERTIES>();\n        cl_platform platform = -1;\n        for( int i = 0; i < props.size(); ++i ) {\n            if( props[i] == CL_CONTEXT_PLATFORM ) {\n                platform = props[i+1];\n            }\n        }\n        CL_HPP_INIT_CL_EXT_FCN_PTR_PLATFORM_(platform, clCreateFromD3D10BufferKHR);\n#elif CL_HPP_TARGET_OPENCL_VERSION >= 110\n        CL_HPP_INIT_CL_EXT_FCN_PTR_(clCreateFromD3D10BufferKHR);\n#endif\n\n        cl_int error;\n        object_ = pfn_clCreateFromD3D10BufferKHR(\n            context(),\n            flags,\n            bufobj,\n            &error);\n\n        detail::errHandler(error, __CREATE_GL_BUFFER_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    //! \\brief Default constructor - initializes to NULL.\n    BufferD3D10() : Buffer() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with \n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit BufferD3D10(const cl_mem& buffer, bool retainObject = false) : \n        Buffer(buffer, retainObject) { }\n\n    /*! \\brief Assignment from cl_mem - performs shallow copy.\n     *\n     *  See Memory for further details.\n     */\n    BufferD3D10& operator = (const cl_mem& rhs)\n    {\n        Buffer::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    BufferD3D10(const BufferD3D10& buf) : \n        Buffer(buf) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    BufferD3D10& operator = (const BufferD3D10 &buf)\n    {\n        Buffer::operator=(buf);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    BufferD3D10(BufferD3D10&& buf) CL_HPP_NOEXCEPT_ : Buffer(std::move(buf)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    BufferD3D10& operator = (BufferD3D10 &&buf)\n    {\n        Buffer::operator=(std::move(buf));\n        return *this;\n    }\n};\n#endif\n\n/*! \\brief Class interface for GL Buffer Memory Objects.\n *\n *  This is provided to facilitate interoperability with OpenGL.\n * \n *  See Memory for details about copy semantics, etc.\n * \n *  \\see Memory\n */\nclass BufferGL : public Buffer\n{\npublic:\n    /*! \\brief Constructs a BufferGL in a specified context, from a given\n     *         GL buffer.\n     *\n     *  Wraps clCreateFromGLBuffer().\n     */\n    BufferGL(\n        const Context& context,\n        cl_mem_flags flags,\n        cl_GLuint bufobj,\n        cl_int * err = NULL)\n    {\n        cl_int error;\n        object_ = ::clCreateFromGLBuffer(\n            context(),\n            flags,\n            bufobj,\n            &error);\n\n        detail::errHandler(error, __CREATE_GL_BUFFER_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    //! \\brief Default constructor - initializes to NULL.\n    BufferGL() : Buffer() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit BufferGL(const cl_mem& buffer, bool retainObject = false) :\n        Buffer(buffer, retainObject) { }\n\n    /*! \\brief Assignment from cl_mem - performs shallow copy.\n     *\n     *  See Memory for further details.\n     */\n    BufferGL& operator = (const cl_mem& rhs)\n    {\n        Buffer::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    BufferGL(const BufferGL& buf) : Buffer(buf) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    BufferGL& operator = (const BufferGL &buf)\n    {\n        Buffer::operator=(buf);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    BufferGL(BufferGL&& buf) CL_HPP_NOEXCEPT_ : Buffer(std::move(buf)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    BufferGL& operator = (BufferGL &&buf)\n    {\n        Buffer::operator=(std::move(buf));\n        return *this;\n    }\n\n    //! \\brief Wrapper for clGetGLObjectInfo().\n    cl_int getObjectInfo(\n        cl_gl_object_type *type,\n        cl_GLuint * gl_object_name)\n    {\n        return detail::errHandler(\n            ::clGetGLObjectInfo(object_,type,gl_object_name),\n            __GET_GL_OBJECT_INFO_ERR);\n    }\n};\n\n/*! \\brief Class interface for GL Render Buffer Memory Objects.\n *\n *  This is provided to facilitate interoperability with OpenGL.\n * \n *  See Memory for details about copy semantics, etc.\n * \n *  \\see Memory\n */\nclass BufferRenderGL : public Buffer\n{\npublic:\n    /*! \\brief Constructs a BufferRenderGL in a specified context, from a given\n     *         GL Renderbuffer.\n     *\n     *  Wraps clCreateFromGLRenderbuffer().\n     */\n    BufferRenderGL(\n        const Context& context,\n        cl_mem_flags flags,\n        cl_GLuint bufobj,\n        cl_int * err = NULL)\n    {\n        cl_int error;\n        object_ = ::clCreateFromGLRenderbuffer(\n            context(),\n            flags,\n            bufobj,\n            &error);\n\n        detail::errHandler(error, __CREATE_GL_RENDER_BUFFER_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    //! \\brief Default constructor - initializes to NULL.\n    BufferRenderGL() : Buffer() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with \n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit BufferRenderGL(const cl_mem& buffer, bool retainObject = false) :\n        Buffer(buffer, retainObject) { }\n\n    /*! \\brief Assignment from cl_mem - performs shallow copy.\n     *\n     *  See Memory for further details.\n     */\n    BufferRenderGL& operator = (const cl_mem& rhs)\n    {\n        Buffer::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    BufferRenderGL(const BufferRenderGL& buf) : Buffer(buf) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    BufferRenderGL& operator = (const BufferRenderGL &buf)\n    {\n        Buffer::operator=(buf);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    BufferRenderGL(BufferRenderGL&& buf) CL_HPP_NOEXCEPT_ : Buffer(std::move(buf)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    BufferRenderGL& operator = (BufferRenderGL &&buf)\n    {\n        Buffer::operator=(std::move(buf));\n        return *this;\n    }\n\n    //! \\brief Wrapper for clGetGLObjectInfo().\n    cl_int getObjectInfo(\n        cl_gl_object_type *type,\n        cl_GLuint * gl_object_name)\n    {\n        return detail::errHandler(\n            ::clGetGLObjectInfo(object_,type,gl_object_name),\n            __GET_GL_OBJECT_INFO_ERR);\n    }\n};\n\n/*! \\brief C++ base class for Image Memory objects.\n *\n *  See Memory for details about copy semantics, etc.\n * \n *  \\see Memory\n */\nclass Image : public Memory\n{\nprotected:\n    //! \\brief Default constructor - initializes to NULL.\n    Image() : Memory() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit Image(const cl_mem& image, bool retainObject = false) :\n        Memory(image, retainObject) { }\n\n    /*! \\brief Assignment from cl_mem - performs shallow copy.\n     *\n     *  See Memory for further details.\n     */\n    Image& operator = (const cl_mem& rhs)\n    {\n        Memory::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image(const Image& img) : Memory(img) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image& operator = (const Image &img)\n    {\n        Memory::operator=(img);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image(Image&& img) CL_HPP_NOEXCEPT_ : Memory(std::move(img)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image& operator = (Image &&img)\n    {\n        Memory::operator=(std::move(img));\n        return *this;\n    }\n\n\npublic:\n    //! \\brief Wrapper for clGetImageInfo().\n    template <typename T>\n    cl_int getImageInfo(cl_image_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(&::clGetImageInfo, object_, name, param),\n            __GET_IMAGE_INFO_ERR);\n    }\n    \n    //! \\brief Wrapper for clGetImageInfo() that returns by value.\n    template <cl_image_info name> typename\n    detail::param_traits<detail::cl_image_info, name>::param_type\n    getImageInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_image_info, name>::param_type param;\n        cl_int result = getImageInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n};\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n/*! \\brief Class interface for 1D Image Memory objects.\n *\n *  See Memory for details about copy semantics, etc.\n * \n *  \\see Memory\n */\nclass Image1D : public Image\n{\npublic:\n    /*! \\brief Constructs a 1D Image in a specified context.\n     *\n     *  Wraps clCreateImage().\n     */\n    Image1D(\n        const Context& context,\n        cl_mem_flags flags,\n        ImageFormat format,\n        size_type width,\n        void* host_ptr = NULL,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        cl_image_desc desc = {0};\n        desc.image_type = CL_MEM_OBJECT_IMAGE1D;\n        desc.image_width = width;\n\n        object_ = ::clCreateImage(\n            context(), \n            flags, \n            &format, \n            &desc, \n            host_ptr, \n            &error);\n\n        detail::errHandler(error, __CREATE_IMAGE_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    //! \\brief Default constructor - initializes to NULL.\n    Image1D() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit Image1D(const cl_mem& image1D, bool retainObject = false) :\n        Image(image1D, retainObject) { }\n\n    /*! \\brief Assignment from cl_mem - performs shallow copy.\n     *\n     *  See Memory for further details.\n     */\n    Image1D& operator = (const cl_mem& rhs)\n    {\n        Image::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image1D(const Image1D& img) : Image(img) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image1D& operator = (const Image1D &img)\n    {\n        Image::operator=(img);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image1D(Image1D&& img) CL_HPP_NOEXCEPT_ : Image(std::move(img)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image1D& operator = (Image1D &&img)\n    {\n        Image::operator=(std::move(img));\n        return *this;\n    }\n\n};\n\n/*! \\class Image1DBuffer\n * \\brief Image interface for 1D buffer images.\n */\nclass Image1DBuffer : public Image\n{\npublic:\n    Image1DBuffer(\n        const Context& context,\n        cl_mem_flags flags,\n        ImageFormat format,\n        size_type width,\n        const Buffer &buffer,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        cl_image_desc desc = {0};\n        desc.image_type = CL_MEM_OBJECT_IMAGE1D_BUFFER;\n        desc.image_width = width;\n        desc.buffer = buffer();\n\n        object_ = ::clCreateImage(\n            context(), \n            flags, \n            &format, \n            &desc, \n            NULL, \n            &error);\n\n        detail::errHandler(error, __CREATE_IMAGE_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    Image1DBuffer() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit Image1DBuffer(const cl_mem& image1D, bool retainObject = false) :\n        Image(image1D, retainObject) { }\n\n    Image1DBuffer& operator = (const cl_mem& rhs)\n    {\n        Image::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image1DBuffer(const Image1DBuffer& img) : Image(img) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image1DBuffer& operator = (const Image1DBuffer &img)\n    {\n        Image::operator=(img);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image1DBuffer(Image1DBuffer&& img) CL_HPP_NOEXCEPT_ : Image(std::move(img)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image1DBuffer& operator = (Image1DBuffer &&img)\n    {\n        Image::operator=(std::move(img));\n        return *this;\n    }\n\n};\n\n/*! \\class Image1DArray\n * \\brief Image interface for arrays of 1D images.\n */\nclass Image1DArray : public Image\n{\npublic:\n    Image1DArray(\n        const Context& context,\n        cl_mem_flags flags,\n        ImageFormat format,\n        size_type arraySize,\n        size_type width,\n        size_type rowPitch,\n        void* host_ptr = NULL,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        cl_image_desc desc = {0};\n        desc.image_type = CL_MEM_OBJECT_IMAGE1D_ARRAY;\n        desc.image_width = width;\n        desc.image_array_size = arraySize;\n        desc.image_row_pitch = rowPitch;\n\n        object_ = ::clCreateImage(\n            context(), \n            flags, \n            &format, \n            &desc, \n            host_ptr, \n            &error);\n\n        detail::errHandler(error, __CREATE_IMAGE_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    Image1DArray() { }\n  \n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit Image1DArray(const cl_mem& imageArray, bool retainObject = false) :\n        Image(imageArray, retainObject) { }\n\n\n    Image1DArray& operator = (const cl_mem& rhs)\n    {\n        Image::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image1DArray(const Image1DArray& img) : Image(img) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image1DArray& operator = (const Image1DArray &img)\n    {\n        Image::operator=(img);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image1DArray(Image1DArray&& img) CL_HPP_NOEXCEPT_ : Image(std::move(img)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image1DArray& operator = (Image1DArray &&img)\n    {\n        Image::operator=(std::move(img));\n        return *this;\n    }\n\n};\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 120\n\n\n/*! \\brief Class interface for 2D Image Memory objects.\n *\n *  See Memory for details about copy semantics, etc.\n * \n *  \\see Memory\n */\nclass Image2D : public Image\n{\npublic:\n    /*! \\brief Constructs a 2D Image in a specified context.\n     *\n     *  Wraps clCreateImage().\n     */\n    Image2D(\n        const Context& context,\n        cl_mem_flags flags,\n        ImageFormat format,\n        size_type width,\n        size_type height,\n        size_type row_pitch = 0,\n        void* host_ptr = NULL,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n        bool useCreateImage;\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120 && CL_HPP_MINIMUM_OPENCL_VERSION < 120\n        // Run-time decision based on the actual platform\n        {\n            cl_uint version = detail::getContextPlatformVersion(context());\n            useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above\n        }\n#elif CL_HPP_TARGET_OPENCL_VERSION >= 120\n        useCreateImage = true;\n#else\n        useCreateImage = false;\n#endif\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n        if (useCreateImage)\n        {\n            cl_image_desc desc = {0};\n            desc.image_type = CL_MEM_OBJECT_IMAGE2D;\n            desc.image_width = width;\n            desc.image_height = height;\n            desc.image_row_pitch = row_pitch;\n\n            object_ = ::clCreateImage(\n                context(),\n                flags,\n                &format,\n                &desc,\n                host_ptr,\n                &error);\n\n            detail::errHandler(error, __CREATE_IMAGE_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n#if CL_HPP_MINIMUM_OPENCL_VERSION < 120\n        if (!useCreateImage)\n        {\n            object_ = ::clCreateImage2D(\n                context(), flags,&format, width, height, row_pitch, host_ptr, &error);\n\n            detail::errHandler(error, __CREATE_IMAGE2D_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n#endif // CL_HPP_MINIMUM_OPENCL_VERSION < 120\n    }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200 || defined(CL_HPP_USE_CL_IMAGE2D_FROM_BUFFER_KHR)\n    /*! \\brief Constructs a 2D Image from a buffer.\n    * \\note This will share storage with the underlying buffer.\n    *\n    *  Wraps clCreateImage().\n    */\n    Image2D(\n        const Context& context,\n        ImageFormat format,\n        const Buffer &sourceBuffer,\n        size_type width,\n        size_type height,\n        size_type row_pitch = 0,\n        cl_int* err = nullptr)\n    {\n        cl_int error;\n\n        cl_image_desc desc = {0};\n        desc.image_type = CL_MEM_OBJECT_IMAGE2D;\n        desc.image_width = width;\n        desc.image_height = height;\n        desc.image_row_pitch = row_pitch;\n        desc.buffer = sourceBuffer();\n\n        object_ = ::clCreateImage(\n            context(),\n            0, // flags inherited from buffer\n            &format,\n            &desc,\n            nullptr,\n            &error);\n\n        detail::errHandler(error, __CREATE_IMAGE_ERR);\n        if (err != nullptr) {\n            *err = error;\n        }\n    }\n#endif //#if CL_HPP_TARGET_OPENCL_VERSION >= 200 || defined(CL_HPP_USE_CL_IMAGE2D_FROM_BUFFER_KHR)\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n    /*! \\brief Constructs a 2D Image from an image.\n    * \\note This will share storage with the underlying image but may\n    *       reinterpret the channel order and type.\n    *\n    * The image will be created matching with a descriptor matching the source. \n    *\n    * \\param order is the channel order to reinterpret the image data as.\n    *              The channel order may differ as described in the OpenCL \n    *              2.0 API specification.\n    *\n    * Wraps clCreateImage().\n    */\n    Image2D(\n        const Context& context,\n        cl_channel_order order,\n        const Image &sourceImage,\n        cl_int* err = nullptr)\n    {\n        cl_int error;\n\n        // Descriptor fields have to match source image\n        size_type sourceWidth = \n            sourceImage.getImageInfo<CL_IMAGE_WIDTH>();\n        size_type sourceHeight = \n            sourceImage.getImageInfo<CL_IMAGE_HEIGHT>();\n        size_type sourceRowPitch =\n            sourceImage.getImageInfo<CL_IMAGE_ROW_PITCH>();\n        cl_uint sourceNumMIPLevels =\n            sourceImage.getImageInfo<CL_IMAGE_NUM_MIP_LEVELS>();\n        cl_uint sourceNumSamples =\n            sourceImage.getImageInfo<CL_IMAGE_NUM_SAMPLES>();\n        cl_image_format sourceFormat =\n            sourceImage.getImageInfo<CL_IMAGE_FORMAT>();\n\n        // Update only the channel order. \n        // Channel format inherited from source.\n        sourceFormat.image_channel_order = order;\n\n        cl_image_desc desc = {0};\n        desc.image_type = CL_MEM_OBJECT_IMAGE2D;\n        desc.image_width = sourceWidth;\n        desc.image_height = sourceHeight;\n        desc.image_row_pitch = sourceRowPitch;\n        desc.num_mip_levels = sourceNumMIPLevels;\n        desc.num_samples = sourceNumSamples;\n        desc.buffer = sourceImage();\n\n        object_ = ::clCreateImage(\n            context(),\n            0, // flags should be inherited from mem_object\n            &sourceFormat,\n            &desc,\n            nullptr,\n            &error);\n\n        detail::errHandler(error, __CREATE_IMAGE_ERR);\n        if (err != nullptr) {\n            *err = error;\n        }\n    }\n#endif //#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\n    //! \\brief Default constructor - initializes to NULL.\n    Image2D() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit Image2D(const cl_mem& image2D, bool retainObject = false) :\n        Image(image2D, retainObject) { }\n\n    /*! \\brief Assignment from cl_mem - performs shallow copy.\n     *\n     *  See Memory for further details.\n     */\n    Image2D& operator = (const cl_mem& rhs)\n    {\n        Image::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image2D(const Image2D& img) : Image(img) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image2D& operator = (const Image2D &img)\n    {\n        Image::operator=(img);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image2D(Image2D&& img) CL_HPP_NOEXCEPT_ : Image(std::move(img)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image2D& operator = (Image2D &&img)\n    {\n        Image::operator=(std::move(img));\n        return *this;\n    }\n\n};\n\n\n#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS)\n/*! \\brief Class interface for GL 2D Image Memory objects.\n *\n *  This is provided to facilitate interoperability with OpenGL.\n * \n *  See Memory for details about copy semantics, etc.\n * \n *  \\see Memory\n *  \\note Deprecated for OpenCL 1.2. Please use ImageGL instead.\n */\nclass CL_API_PREFIX__VERSION_1_1_DEPRECATED Image2DGL : public Image2D \n{\npublic:\n    /*! \\brief Constructs an Image2DGL in a specified context, from a given\n     *         GL Texture.\n     *\n     *  Wraps clCreateFromGLTexture2D().\n     */\n    Image2DGL(\n        const Context& context,\n        cl_mem_flags flags,\n        cl_GLenum target,\n        cl_GLint  miplevel,\n        cl_GLuint texobj,\n        cl_int * err = NULL)\n    {\n        cl_int error;\n        object_ = ::clCreateFromGLTexture2D(\n            context(),\n            flags,\n            target,\n            miplevel,\n            texobj,\n            &error);\n\n        detail::errHandler(error, __CREATE_GL_TEXTURE_2D_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n\n    }\n    \n    //! \\brief Default constructor - initializes to NULL.\n    Image2DGL() : Image2D() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit Image2DGL(const cl_mem& image, bool retainObject = false) : \n        Image2D(image, retainObject) { }\n\n    /*! \\brief Assignment from cl_mem - performs shallow copy.\n     *c\n     *  See Memory for further details.\n     */\n    Image2DGL& operator = (const cl_mem& rhs)\n    {\n        Image2D::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image2DGL(const Image2DGL& img) : Image2D(img) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image2DGL& operator = (const Image2DGL &img)\n    {\n        Image2D::operator=(img);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image2DGL(Image2DGL&& img) CL_HPP_NOEXCEPT_ : Image2D(std::move(img)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image2DGL& operator = (Image2DGL &&img)\n    {\n        Image2D::operator=(std::move(img));\n        return *this;\n    }\n\n} CL_API_SUFFIX__VERSION_1_1_DEPRECATED;\n#endif // CL_USE_DEPRECATED_OPENCL_1_1_APIS\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n/*! \\class Image2DArray\n * \\brief Image interface for arrays of 2D images.\n */\nclass Image2DArray : public Image\n{\npublic:\n    Image2DArray(\n        const Context& context,\n        cl_mem_flags flags,\n        ImageFormat format,\n        size_type arraySize,\n        size_type width,\n        size_type height,\n        size_type rowPitch,\n        size_type slicePitch,\n        void* host_ptr = NULL,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        cl_image_desc desc = {0};\n        desc.image_type = CL_MEM_OBJECT_IMAGE2D_ARRAY;\n        desc.image_width = width;\n        desc.image_height = height;\n        desc.image_array_size = arraySize;\n        desc.image_row_pitch = rowPitch;\n        desc.image_slice_pitch = slicePitch;\n\n        object_ = ::clCreateImage(\n            context(), \n            flags, \n            &format, \n            &desc, \n            host_ptr, \n            &error);\n\n        detail::errHandler(error, __CREATE_IMAGE_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    Image2DArray() { }\n    \n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit Image2DArray(const cl_mem& imageArray, bool retainObject = false) : Image(imageArray, retainObject) { }\n\n    Image2DArray& operator = (const cl_mem& rhs)\n    {\n        Image::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image2DArray(const Image2DArray& img) : Image(img) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image2DArray& operator = (const Image2DArray &img)\n    {\n        Image::operator=(img);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image2DArray(Image2DArray&& img) CL_HPP_NOEXCEPT_ : Image(std::move(img)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image2DArray& operator = (Image2DArray &&img)\n    {\n        Image::operator=(std::move(img));\n        return *this;\n    }\n};\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 120\n\n/*! \\brief Class interface for 3D Image Memory objects.\n *\n *  See Memory for details about copy semantics, etc.\n * \n *  \\see Memory\n */\nclass Image3D : public Image\n{\npublic:\n    /*! \\brief Constructs a 3D Image in a specified context.\n     *\n     *  Wraps clCreateImage().\n     */\n    Image3D(\n        const Context& context,\n        cl_mem_flags flags,\n        ImageFormat format,\n        size_type width,\n        size_type height,\n        size_type depth,\n        size_type row_pitch = 0,\n        size_type slice_pitch = 0,\n        void* host_ptr = NULL,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n        bool useCreateImage;\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120 && CL_HPP_MINIMUM_OPENCL_VERSION < 120\n        // Run-time decision based on the actual platform\n        {\n            cl_uint version = detail::getContextPlatformVersion(context());\n            useCreateImage = (version >= 0x10002); // OpenCL 1.2 or above\n        }\n#elif CL_HPP_TARGET_OPENCL_VERSION >= 120\n        useCreateImage = true;\n#else\n        useCreateImage = false;\n#endif\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n        if (useCreateImage)\n        {\n            cl_image_desc desc = {0};\n            desc.image_type = CL_MEM_OBJECT_IMAGE3D;\n            desc.image_width = width;\n            desc.image_height = height;\n            desc.image_depth = depth;\n            desc.image_row_pitch = row_pitch;\n            desc.image_slice_pitch = slice_pitch;\n\n            object_ = ::clCreateImage(\n                context(), \n                flags, \n                &format, \n                &desc, \n                host_ptr, \n                &error);\n\n            detail::errHandler(error, __CREATE_IMAGE_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n#endif  // CL_HPP_TARGET_OPENCL_VERSION >= 120\n#if CL_HPP_MINIMUM_OPENCL_VERSION < 120\n        if (!useCreateImage)\n        {\n            object_ = ::clCreateImage3D(\n                context(), flags, &format, width, height, depth, row_pitch,\n                slice_pitch, host_ptr, &error);\n\n            detail::errHandler(error, __CREATE_IMAGE3D_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n#endif // CL_HPP_MINIMUM_OPENCL_VERSION < 120\n    }\n\n    //! \\brief Default constructor - initializes to NULL.\n    Image3D() : Image() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit Image3D(const cl_mem& image3D, bool retainObject = false) : \n        Image(image3D, retainObject) { }\n\n    /*! \\brief Assignment from cl_mem - performs shallow copy.\n     *\n     *  See Memory for further details.\n     */\n    Image3D& operator = (const cl_mem& rhs)\n    {\n        Image::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image3D(const Image3D& img) : Image(img) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image3D& operator = (const Image3D &img)\n    {\n        Image::operator=(img);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image3D(Image3D&& img) CL_HPP_NOEXCEPT_ : Image(std::move(img)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image3D& operator = (Image3D &&img)\n    {\n        Image::operator=(std::move(img));\n        return *this;\n    }\n};\n\n#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS)\n/*! \\brief Class interface for GL 3D Image Memory objects.\n *\n *  This is provided to facilitate interoperability with OpenGL.\n * \n *  See Memory for details about copy semantics, etc.\n * \n *  \\see Memory\n */\nclass Image3DGL : public Image3D\n{\npublic:\n    /*! \\brief Constructs an Image3DGL in a specified context, from a given\n     *         GL Texture.\n     *\n     *  Wraps clCreateFromGLTexture3D().\n     */\n    Image3DGL(\n        const Context& context,\n        cl_mem_flags flags,\n        cl_GLenum target,\n        cl_GLint  miplevel,\n        cl_GLuint texobj,\n        cl_int * err = NULL)\n    {\n        cl_int error;\n        object_ = ::clCreateFromGLTexture3D(\n            context(),\n            flags,\n            target,\n            miplevel,\n            texobj,\n            &error);\n\n        detail::errHandler(error, __CREATE_GL_TEXTURE_3D_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    //! \\brief Default constructor - initializes to NULL.\n    Image3DGL() : Image3D() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit Image3DGL(const cl_mem& image, bool retainObject = false) : \n        Image3D(image, retainObject) { }\n\n    /*! \\brief Assignment from cl_mem - performs shallow copy.\n     *\n     *  See Memory for further details.\n     */\n    Image3DGL& operator = (const cl_mem& rhs)\n    {\n        Image3D::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image3DGL(const Image3DGL& img) : Image3D(img) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image3DGL& operator = (const Image3DGL &img)\n    {\n        Image3D::operator=(img);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image3DGL(Image3DGL&& img) CL_HPP_NOEXCEPT_ : Image3D(std::move(img)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Image3DGL& operator = (Image3DGL &&img)\n    {\n        Image3D::operator=(std::move(img));\n        return *this;\n    }\n};\n#endif // CL_USE_DEPRECATED_OPENCL_1_1_APIS\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n/*! \\class ImageGL\n * \\brief general image interface for GL interop.\n * We abstract the 2D and 3D GL images into a single instance here\n * that wraps all GL sourced images on the grounds that setup information\n * was performed by OpenCL anyway.\n */\nclass ImageGL : public Image\n{\npublic:\n    ImageGL(\n        const Context& context,\n        cl_mem_flags flags,\n        cl_GLenum target,\n        cl_GLint  miplevel,\n        cl_GLuint texobj,\n        cl_int * err = NULL)\n    {\n        cl_int error;\n        object_ = ::clCreateFromGLTexture(\n            context(), \n            flags, \n            target,\n            miplevel,\n            texobj,\n            &error);\n\n        detail::errHandler(error, __CREATE_GL_TEXTURE_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    ImageGL() : Image() { }\n    \n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  See Memory for further details.\n     */\n    explicit ImageGL(const cl_mem& image, bool retainObject = false) : \n        Image(image, retainObject) { }\n\n    ImageGL& operator = (const cl_mem& rhs)\n    {\n        Image::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    ImageGL(const ImageGL& img) : Image(img) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    ImageGL& operator = (const ImageGL &img)\n    {\n        Image::operator=(img);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    ImageGL(ImageGL&& img) CL_HPP_NOEXCEPT_ : Image(std::move(img)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    ImageGL& operator = (ImageGL &&img)\n    {\n        Image::operator=(std::move(img));\n        return *this;\n    }\n};\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n\n\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n/*! \\brief Class interface for Pipe Memory Objects.\n*\n*  See Memory for details about copy semantics, etc.\n*\n*  \\see Memory\n*/\nclass Pipe : public Memory\n{\npublic:\n\n    /*! \\brief Constructs a Pipe in a specified context.\n     *\n     * Wraps clCreatePipe().\n     * @param context Context in which to create the pipe.\n     * @param flags Bitfield. Only CL_MEM_READ_WRITE and CL_MEM_HOST_NO_ACCESS are valid.\n     * @param packet_size Size in bytes of a single packet of the pipe.\n     * @param max_packets Number of packets that may be stored in the pipe.\n     *\n     */\n    Pipe(\n        const Context& context,\n        cl_uint packet_size,\n        cl_uint max_packets,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        cl_mem_flags flags = CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS;\n        object_ = ::clCreatePipe(context(), flags, packet_size, max_packets, nullptr, &error);\n\n        detail::errHandler(error, __CREATE_PIPE_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    /*! \\brief Constructs a Pipe in a the default context.\n     *\n     * Wraps clCreatePipe().\n     * @param flags Bitfield. Only CL_MEM_READ_WRITE and CL_MEM_HOST_NO_ACCESS are valid.\n     * @param packet_size Size in bytes of a single packet of the pipe.\n     * @param max_packets Number of packets that may be stored in the pipe.\n     *\n     */\n    Pipe(\n        cl_uint packet_size,\n        cl_uint max_packets,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        Context context = Context::getDefault(err);\n\n        cl_mem_flags flags = CL_MEM_READ_WRITE | CL_MEM_HOST_NO_ACCESS;\n        object_ = ::clCreatePipe(context(), flags, packet_size, max_packets, nullptr, &error);\n\n        detail::errHandler(error, __CREATE_PIPE_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    //! \\brief Default constructor - initializes to NULL.\n    Pipe() : Memory() { }\n\n    /*! \\brief Constructor from cl_mem - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with earlier versions.\n     *\n     *  See Memory for further details.\n     */\n    explicit Pipe(const cl_mem& pipe, bool retainObject = false) :\n        Memory(pipe, retainObject) { }\n\n    /*! \\brief Assignment from cl_mem - performs shallow copy.\n     *\n     *  See Memory for further details.\n     */\n    Pipe& operator = (const cl_mem& rhs)\n    {\n        Memory::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Pipe(const Pipe& pipe) : Memory(pipe) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Pipe& operator = (const Pipe &pipe)\n    {\n        Memory::operator=(pipe);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Pipe(Pipe&& pipe) CL_HPP_NOEXCEPT_ : Memory(std::move(pipe)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Pipe& operator = (Pipe &&pipe)\n    {\n        Memory::operator=(std::move(pipe));\n        return *this;\n    }\n\n    //! \\brief Wrapper for clGetMemObjectInfo().\n    template <typename T>\n    cl_int getInfo(cl_pipe_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(&::clGetPipeInfo, object_, name, param),\n            __GET_PIPE_INFO_ERR);\n    }\n\n    //! \\brief Wrapper for clGetMemObjectInfo() that returns by value.\n    template <cl_pipe_info name> typename\n        detail::param_traits<detail::cl_pipe_info, name>::param_type\n        getInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_pipe_info, name>::param_type param;\n        cl_int result = getInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n}; // class Pipe\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 200\n\n\n/*! \\brief Class interface for cl_sampler.\n *\n *  \\note Copies of these objects are shallow, meaning that the copy will refer\n *        to the same underlying cl_sampler as the original.  For details, see\n *        clRetainSampler() and clReleaseSampler().\n *\n *  \\see cl_sampler \n */\nclass Sampler : public detail::Wrapper<cl_sampler>\n{\npublic:\n    //! \\brief Default constructor - initializes to NULL.\n    Sampler() { }\n\n    /*! \\brief Constructs a Sampler in a specified context.\n     *\n     *  Wraps clCreateSampler().\n     */\n    Sampler(\n        const Context& context,\n        cl_bool normalized_coords,\n        cl_addressing_mode addressing_mode,\n        cl_filter_mode filter_mode,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n        cl_sampler_properties sampler_properties[] = {\n            CL_SAMPLER_NORMALIZED_COORDS, normalized_coords,\n            CL_SAMPLER_ADDRESSING_MODE, addressing_mode,\n            CL_SAMPLER_FILTER_MODE, filter_mode,\n            0 };\n        object_ = ::clCreateSamplerWithProperties(\n            context(),\n            sampler_properties,\n            &error);\n\n        detail::errHandler(error, __CREATE_SAMPLER_WITH_PROPERTIES_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n#else\n        object_ = ::clCreateSampler(\n            context(),\n            normalized_coords,\n            addressing_mode,\n            filter_mode,\n            &error);\n\n        detail::errHandler(error, __CREATE_SAMPLER_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n#endif        \n    }\n\n    /*! \\brief Constructor from cl_sampler - takes ownership.\n     * \n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  This effectively transfers ownership of a refcount on the cl_sampler\n     *  into the new Sampler object.\n     */\n    explicit Sampler(const cl_sampler& sampler, bool retainObject = false) : \n        detail::Wrapper<cl_type>(sampler, retainObject) { }\n\n    /*! \\brief Assignment operator from cl_sampler - takes ownership.\n     *\n     *  This effectively transfers ownership of a refcount on the rhs and calls\n     *  clReleaseSampler() on the value previously held by this instance.\n     */\n    Sampler& operator = (const cl_sampler& rhs)\n    {\n        detail::Wrapper<cl_type>::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Sampler(const Sampler& sam) : detail::Wrapper<cl_type>(sam) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Sampler& operator = (const Sampler &sam)\n    {\n        detail::Wrapper<cl_type>::operator=(sam);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Sampler(Sampler&& sam) CL_HPP_NOEXCEPT_ : detail::Wrapper<cl_type>(std::move(sam)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Sampler& operator = (Sampler &&sam)\n    {\n        detail::Wrapper<cl_type>::operator=(std::move(sam));\n        return *this;\n    }\n\n    //! \\brief Wrapper for clGetSamplerInfo().\n    template <typename T>\n    cl_int getInfo(cl_sampler_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(&::clGetSamplerInfo, object_, name, param),\n            __GET_SAMPLER_INFO_ERR);\n    }\n\n    //! \\brief Wrapper for clGetSamplerInfo() that returns by value.\n    template <cl_sampler_info name> typename\n    detail::param_traits<detail::cl_sampler_info, name>::param_type\n    getInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_sampler_info, name>::param_type param;\n        cl_int result = getInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n};\n\nclass Program;\nclass CommandQueue;\nclass DeviceCommandQueue;\nclass Kernel;\n\n//! \\brief Class interface for specifying NDRange values.\nclass NDRange\n{\nprivate:\n    size_type sizes_[3];\n    cl_uint dimensions_;\n\npublic:\n    //! \\brief Default constructor - resulting range has zero dimensions.\n    NDRange()\n        : dimensions_(0)\n    {\n        sizes_[0] = 0;\n        sizes_[1] = 0;\n        sizes_[2] = 0;\n    }\n\n    //! \\brief Constructs one-dimensional range.\n    NDRange(size_type size0)\n        : dimensions_(1)\n    {\n        sizes_[0] = size0;\n        sizes_[1] = 1;\n        sizes_[2] = 1;\n    }\n\n    //! \\brief Constructs two-dimensional range.\n    NDRange(size_type size0, size_type size1)\n        : dimensions_(2)\n    {\n        sizes_[0] = size0;\n        sizes_[1] = size1;\n        sizes_[2] = 1;\n    }\n\n    //! \\brief Constructs three-dimensional range.\n    NDRange(size_type size0, size_type size1, size_type size2)\n        : dimensions_(3)\n    {\n        sizes_[0] = size0;\n        sizes_[1] = size1;\n        sizes_[2] = size2;\n    }\n\n    /*! \\brief Conversion operator to const size_type *.\n     *  \n     *  \\returns a pointer to the size of the first dimension.\n     */\n    operator const size_type*() const { \n        return sizes_; \n    }\n\n    //! \\brief Queries the number of dimensions in the range.\n    size_type dimensions() const \n    { \n        return dimensions_; \n    }\n\n    //! \\brief Returns the size of the object in bytes based on the\n    // runtime number of dimensions\n    size_type size() const\n    {\n        return dimensions_*sizeof(size_type);\n    }\n\n    size_type* get()\n    {\n        return sizes_;\n    }\n    \n    const size_type* get() const\n    {\n        return sizes_;\n    }\n};\n\n//! \\brief A zero-dimensional range.\nstatic const NDRange NullRange;\n\n//! \\brief Local address wrapper for use with Kernel::setArg\nstruct LocalSpaceArg\n{\n    size_type size_;\n};\n\nnamespace detail {\n\ntemplate <typename T, class Enable = void>\nstruct KernelArgumentHandler;\n\n// Enable for objects that are not subclasses of memory\n// Pointers, constants etc\ntemplate <typename T>\nstruct KernelArgumentHandler<T, typename std::enable_if<!std::is_base_of<cl::Memory, T>::value>::type>\n{\n    static size_type size(const T&) { return sizeof(T); }\n    static const T* ptr(const T& value) { return &value; }\n};\n\n// Enable for subclasses of memory where we want to get a reference to the cl_mem out\n// and pass that in for safety\ntemplate <typename T>\nstruct KernelArgumentHandler<T, typename std::enable_if<std::is_base_of<cl::Memory, T>::value>::type>\n{\n    static size_type size(const T&) { return sizeof(cl_mem); }\n    static const cl_mem* ptr(const T& value) { return &(value()); }\n};\n\n// Specialization for DeviceCommandQueue defined later\n\ntemplate <>\nstruct KernelArgumentHandler<LocalSpaceArg, void>\n{\n    static size_type size(const LocalSpaceArg& value) { return value.size_; }\n    static const void* ptr(const LocalSpaceArg&) { return NULL; }\n};\n\n} \n//! \\endcond\n\n/*! Local\n * \\brief Helper function for generating LocalSpaceArg objects.\n */\ninline LocalSpaceArg\nLocal(size_type size)\n{\n    LocalSpaceArg ret = { size };\n    return ret;\n}\n\n/*! \\brief Class interface for cl_kernel.\n *\n *  \\note Copies of these objects are shallow, meaning that the copy will refer\n *        to the same underlying cl_kernel as the original.  For details, see\n *        clRetainKernel() and clReleaseKernel().\n *\n *  \\see cl_kernel\n */\nclass Kernel : public detail::Wrapper<cl_kernel>\n{\npublic:\n    inline Kernel(const Program& program, const char* name, cl_int* err = NULL);\n\n    //! \\brief Default constructor - initializes to NULL.\n    Kernel() { }\n\n    /*! \\brief Constructor from cl_kernel - takes ownership.\n     * \n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     *  This effectively transfers ownership of a refcount on the cl_kernel\n     *  into the new Kernel object.\n     */\n    explicit Kernel(const cl_kernel& kernel, bool retainObject = false) : \n        detail::Wrapper<cl_type>(kernel, retainObject) { }\n\n    /*! \\brief Assignment operator from cl_kernel - takes ownership.\n     *\n     *  This effectively transfers ownership of a refcount on the rhs and calls\n     *  clReleaseKernel() on the value previously held by this instance.\n     */\n    Kernel& operator = (const cl_kernel& rhs)\n    {\n        detail::Wrapper<cl_type>::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Kernel(const Kernel& kernel) : detail::Wrapper<cl_type>(kernel) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Kernel& operator = (const Kernel &kernel)\n    {\n        detail::Wrapper<cl_type>::operator=(kernel);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Kernel(Kernel&& kernel) CL_HPP_NOEXCEPT_ : detail::Wrapper<cl_type>(std::move(kernel)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Kernel& operator = (Kernel &&kernel)\n    {\n        detail::Wrapper<cl_type>::operator=(std::move(kernel));\n        return *this;\n    }\n\n    template <typename T>\n    cl_int getInfo(cl_kernel_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(&::clGetKernelInfo, object_, name, param),\n            __GET_KERNEL_INFO_ERR);\n    }\n\n    template <cl_kernel_info name> typename\n    detail::param_traits<detail::cl_kernel_info, name>::param_type\n    getInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_kernel_info, name>::param_type param;\n        cl_int result = getInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n    template <typename T>\n    cl_int getArgInfo(cl_uint argIndex, cl_kernel_arg_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(&::clGetKernelArgInfo, object_, argIndex, name, param),\n            __GET_KERNEL_ARG_INFO_ERR);\n    }\n\n    template <cl_kernel_arg_info name> typename\n    detail::param_traits<detail::cl_kernel_arg_info, name>::param_type\n    getArgInfo(cl_uint argIndex, cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_kernel_arg_info, name>::param_type param;\n        cl_int result = getArgInfo(argIndex, name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n\n    template <typename T>\n    cl_int getWorkGroupInfo(\n        const Device& device, cl_kernel_work_group_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(\n                &::clGetKernelWorkGroupInfo, object_, device(), name, param),\n                __GET_KERNEL_WORK_GROUP_INFO_ERR);\n    }\n\n    template <cl_kernel_work_group_info name> typename\n    detail::param_traits<detail::cl_kernel_work_group_info, name>::param_type\n        getWorkGroupInfo(const Device& device, cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n        detail::cl_kernel_work_group_info, name>::param_type param;\n        cl_int result = getWorkGroupInfo(device, name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n    \n#if (CL_HPP_TARGET_OPENCL_VERSION >= 200 && defined(CL_HPP_USE_CL_SUB_GROUPS_KHR)) || CL_HPP_TARGET_OPENCL_VERSION >= 210\n    cl_int getSubGroupInfo(const cl::Device &dev, cl_kernel_sub_group_info name, const cl::NDRange &range, size_type* param) const\n    {\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210\n\n        return detail::errHandler(\n            clGetKernelSubGroupInfo(object_, dev(), name, range.size(), range.get(), sizeof(size_type), param, nullptr),\n            __GET_KERNEL_SUB_GROUP_INFO_ERR);\n\n#else // #if CL_HPP_TARGET_OPENCL_VERSION >= 210\n\n        typedef clGetKernelSubGroupInfoKHR_fn PFN_clGetKernelSubGroupInfoKHR;\n        static PFN_clGetKernelSubGroupInfoKHR pfn_clGetKernelSubGroupInfoKHR = NULL;\n        CL_HPP_INIT_CL_EXT_FCN_PTR_(clGetKernelSubGroupInfoKHR);\n\n        return detail::errHandler(\n            pfn_clGetKernelSubGroupInfoKHR(object_, dev(), name, range.size(), range.get(), sizeof(size_type), param, nullptr),\n            __GET_KERNEL_SUB_GROUP_INFO_ERR);\n\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 210\n    }\n\n    template <cl_kernel_sub_group_info name>\n        size_type getSubGroupInfo(const cl::Device &dev, const cl::NDRange &range, cl_int* err = NULL) const\n    {\n        size_type param;\n        cl_int result = getSubGroupInfo(dev, name, range, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n    /*! \\brief setArg overload taking a shared_ptr type\n     */\n    template<typename T, class D>\n    cl_int setArg(cl_uint index, const cl::pointer<T, D> &argPtr)\n    {\n        return detail::errHandler(\n            ::clSetKernelArgSVMPointer(object_, index, argPtr.get()),\n            __SET_KERNEL_ARGS_ERR);\n    }\n\n    /*! \\brief setArg overload taking a vector type.\n     */\n    template<typename T, class Alloc>\n    cl_int setArg(cl_uint index, const cl::vector<T, Alloc> &argPtr)\n    {\n        return detail::errHandler(\n            ::clSetKernelArgSVMPointer(object_, index, argPtr.data()),\n            __SET_KERNEL_ARGS_ERR);\n    }\n\n    /*! \\brief setArg overload taking a pointer type\n     */\n    template<typename T>\n    typename std::enable_if<std::is_pointer<T>::value, cl_int>::type\n        setArg(cl_uint index, const T argPtr)\n    {\n        return detail::errHandler(\n            ::clSetKernelArgSVMPointer(object_, index, argPtr),\n            __SET_KERNEL_ARGS_ERR);\n    }\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\n    /*! \\brief setArg overload taking a POD type\n     */\n    template <typename T>\n    typename std::enable_if<!std::is_pointer<T>::value, cl_int>::type\n        setArg(cl_uint index, const T &value)\n    {\n        return detail::errHandler(\n            ::clSetKernelArg(\n                object_,\n                index,\n                detail::KernelArgumentHandler<T>::size(value),\n                detail::KernelArgumentHandler<T>::ptr(value)),\n            __SET_KERNEL_ARGS_ERR);\n    }\n\n    cl_int setArg(cl_uint index, size_type size, const void* argPtr)\n    {\n        return detail::errHandler(\n            ::clSetKernelArg(object_, index, size, argPtr),\n            __SET_KERNEL_ARGS_ERR);\n    }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n    /*!\n     * Specify a vector of SVM pointers that the kernel may access in \n     * addition to its arguments.\n     */\n    cl_int setSVMPointers(const vector<void*> &pointerList)\n    {\n        return detail::errHandler(\n            ::clSetKernelExecInfo(\n                object_,\n                CL_KERNEL_EXEC_INFO_SVM_PTRS,\n                sizeof(void*)*pointerList.size(),\n                pointerList.data()));\n    }\n\n    /*!\n     * Specify a std::array of SVM pointers that the kernel may access in\n     * addition to its arguments.\n     */\n    template<int ArrayLength>\n    cl_int setSVMPointers(const std::array<void*, ArrayLength> &pointerList)\n    {\n        return detail::errHandler(\n            ::clSetKernelExecInfo(\n                object_,\n                CL_KERNEL_EXEC_INFO_SVM_PTRS,\n                sizeof(void*)*pointerList.size(),\n                pointerList.data()));\n    }\n\n    /*! \\brief Enable fine-grained system SVM.\n     *\n     * \\note It is only possible to enable fine-grained system SVM if all devices\n     *       in the context associated with kernel support it.\n     * \n     * \\param svmEnabled True if fine-grained system SVM is requested. False otherwise.\n     * \\return CL_SUCCESS if the function was executed succesfully. CL_INVALID_OPERATION\n     *         if no devices in the context support fine-grained system SVM.\n     *\n     * \\see clSetKernelExecInfo\n     */\n    cl_int enableFineGrainedSystemSVM(bool svmEnabled)\n    {\n        cl_bool svmEnabled_ = svmEnabled ? CL_TRUE : CL_FALSE;\n        return detail::errHandler(\n            ::clSetKernelExecInfo(\n                object_,\n                CL_KERNEL_EXEC_INFO_SVM_FINE_GRAIN_SYSTEM,\n                sizeof(cl_bool),\n                &svmEnabled_\n                )\n            );\n    }\n    \n    template<int index, int ArrayLength, class D, typename T0, typename T1, typename... Ts>\n    void setSVMPointersHelper(std::array<void*, ArrayLength> &pointerList, const pointer<T0, D> &t0, const pointer<T1, D> &t1, Ts & ... ts)\n    {\n        pointerList[index] = static_cast<void*>(t0.get());\n        setSVMPointersHelper<index + 1, ArrayLength>(pointerList, t1, ts...);\n    }\n\n    template<int index, int ArrayLength, typename T0, typename T1, typename... Ts>\n    typename std::enable_if<std::is_pointer<T0>::value, void>::type\n    setSVMPointersHelper(std::array<void*, ArrayLength> &pointerList, T0 t0, T1 t1, Ts... ts)\n    {\n        pointerList[index] = static_cast<void*>(t0);\n        setSVMPointersHelper<index + 1, ArrayLength>(pointerList, t1, ts...);\n    }\n\n    template<int index, int ArrayLength, typename T0, class D>\n    void setSVMPointersHelper(std::array<void*, ArrayLength> &pointerList, const pointer<T0, D> &t0)\n    {\n        pointerList[index] = static_cast<void*>(t0.get());\n    }\n\n\n    template<int index, int ArrayLength, typename T0>\n    typename std::enable_if<std::is_pointer<T0>::value, void>::type\n    setSVMPointersHelper(std::array<void*, ArrayLength> &pointerList, T0 t0)\n    {\n        pointerList[index] = static_cast<void*>(t0);\n    }\n\n    template<typename T0, typename... Ts>\n    cl_int setSVMPointers(const T0 &t0, Ts & ... ts)\n    {\n        std::array<void*, 1 + sizeof...(Ts)> pointerList;\n\n        setSVMPointersHelper<0, 1 + sizeof...(Ts)>(pointerList, t0, ts...);\n        return detail::errHandler(\n            ::clSetKernelExecInfo(\n            object_,\n            CL_KERNEL_EXEC_INFO_SVM_PTRS,\n            sizeof(void*)*(1 + sizeof...(Ts)),\n            pointerList.data()));\n    }\n\n    template<typename T>\n    cl_int setExecInfo(cl_kernel_exec_info param_name, const T& val)\n    {\n        return detail::errHandler(\n            ::clSetKernelExecInfo(\n            object_,\n            param_name,\n            sizeof(T),\n            &val));\n    }\n\n    template<cl_kernel_exec_info name>\n    cl_int setExecInfo(typename detail::param_traits<detail::cl_kernel_exec_info, name>::param_type& val)\n    {\n        return setExecInfo(name, val);\n    }\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210\n    /**\n     * Make a deep copy of the kernel object including its arguments.\n     * @return A new kernel object with internal state entirely separate from that\n     *         of the original but with any arguments set on the original intact.\n     */\n    Kernel clone()\n    {\n        cl_int error;\n        Kernel retValue(clCloneKernel(this->get(), &error));\n\n        detail::errHandler(error, __CLONE_KERNEL_ERR);\n        return retValue;\n    }\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 210\n};\n\n/*! \\class Program\n * \\brief Program interface that implements cl_program.\n */\nclass Program : public detail::Wrapper<cl_program>\n{\npublic:\n#if !defined(CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY)\n    typedef vector<vector<unsigned char>> Binaries;\n    typedef vector<string> Sources;\n#else // #if !defined(CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY)\n    typedef vector<std::pair<const void*, size_type> > Binaries;\n    typedef vector<std::pair<const char*, size_type> > Sources;\n#endif // #if !defined(CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY)\n    \n    Program(\n        const string& source,\n        bool build = false,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        const char * strings = source.c_str();\n        const size_type length  = source.size();\n\n        Context context = Context::getDefault(err);\n\n        object_ = ::clCreateProgramWithSource(\n            context(), (cl_uint)1, &strings, &length, &error);\n\n        detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR);\n\n        if (error == CL_SUCCESS && build) {\n\n            error = ::clBuildProgram(\n                object_,\n                0,\n                NULL,\n#if !defined(CL_HPP_CL_1_2_DEFAULT_BUILD)\n                \"-cl-std=CL2.0\",\n#else\n                \"\",\n#endif // #if !defined(CL_HPP_CL_1_2_DEFAULT_BUILD)\n                NULL,\n                NULL);\n\n            detail::buildErrHandler(error, __BUILD_PROGRAM_ERR, getBuildInfo<CL_PROGRAM_BUILD_LOG>());\n        }\n\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    Program(\n        const Context& context,\n        const string& source,\n        bool build = false,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        const char * strings = source.c_str();\n        const size_type length  = source.size();\n\n        object_ = ::clCreateProgramWithSource(\n            context(), (cl_uint)1, &strings, &length, &error);\n\n        detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR);\n\n        if (error == CL_SUCCESS && build) {\n            error = ::clBuildProgram(\n                object_,\n                0,\n                NULL,\n#if !defined(CL_HPP_CL_1_2_DEFAULT_BUILD)\n                \"-cl-std=CL2.0\",\n#else\n                \"\",\n#endif // #if !defined(CL_HPP_CL_1_2_DEFAULT_BUILD)\n                NULL,\n                NULL);\n            \n            detail::buildErrHandler(error, __BUILD_PROGRAM_ERR, getBuildInfo<CL_PROGRAM_BUILD_LOG>());\n        }\n\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    /**\n     * Create a program from a vector of source strings and the default context.\n     * Does not compile or link the program.\n     */\n    Program(\n        const Sources& sources,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n        Context context = Context::getDefault(err);\n\n        const size_type n = (size_type)sources.size();\n\n        vector<size_type> lengths(n);\n        vector<const char*> strings(n);\n\n        for (size_type i = 0; i < n; ++i) {\n#if !defined(CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY)\n            strings[i] = sources[(int)i].data();\n            lengths[i] = sources[(int)i].length();\n#else // #if !defined(CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY)\n            strings[i] = sources[(int)i].first;\n            lengths[i] = sources[(int)i].second;\n#endif // #if !defined(CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY)\n        }\n\n        object_ = ::clCreateProgramWithSource(\n            context(), (cl_uint)n, strings.data(), lengths.data(), &error);\n\n        detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    /**\n     * Create a program from a vector of source strings and a provided context.\n     * Does not compile or link the program.\n     */\n    Program(\n        const Context& context,\n        const Sources& sources,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        const size_type n = (size_type)sources.size();\n\n        vector<size_type> lengths(n);\n        vector<const char*> strings(n);\n\n        for (size_type i = 0; i < n; ++i) {\n#if !defined(CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY)\n            strings[i] = sources[(int)i].data();\n            lengths[i] = sources[(int)i].length();\n#else // #if !defined(CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY)\n            strings[i] = sources[(int)i].first;\n            lengths[i] = sources[(int)i].second;\n#endif // #if !defined(CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY)\n        }\n\n        object_ = ::clCreateProgramWithSource(\n            context(), (cl_uint)n, strings.data(), lengths.data(), &error);\n\n        detail::errHandler(error, __CREATE_PROGRAM_WITH_SOURCE_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210 || (CL_HPP_TARGET_OPENCL_VERSION==200 && defined(CL_HPP_USE_IL_KHR))\n    /**\n     * Program constructor to allow construction of program from SPIR-V or another IL.\n     * Valid for either OpenCL >= 2.1 or when CL_HPP_USE_IL_KHR is defined.\n     */\n    Program(\n        const vector<char>& IL,\n        bool build = false,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        Context context = Context::getDefault(err);\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210\n\n        object_ = ::clCreateProgramWithIL(\n            context(), static_cast<const void*>(IL.data()), IL.size(), &error);\n\n#else // #if CL_HPP_TARGET_OPENCL_VERSION >= 210\n\n        typedef clCreateProgramWithILKHR_fn PFN_clCreateProgramWithILKHR;\n        static PFN_clCreateProgramWithILKHR pfn_clCreateProgramWithILKHR = NULL;\n        CL_HPP_INIT_CL_EXT_FCN_PTR_(clCreateProgramWithILKHR);\n\n        return detail::errHandler(\n            pfn_clCreateProgramWithILKHR(\n                context(), static_cast<const void*>(IL.data()), IL.size(), &error);\n\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 210\n\n        detail::errHandler(error, __CREATE_PROGRAM_WITH_IL_ERR);\n\n        if (error == CL_SUCCESS && build) {\n\n            error = ::clBuildProgram(\n                object_,\n                0,\n                NULL,\n#if !defined(CL_HPP_CL_1_2_DEFAULT_BUILD)\n                \"-cl-std=CL2.0\",\n#else\n                \"\",\n#endif // #if !defined(CL_HPP_CL_1_2_DEFAULT_BUILD)\n                NULL,\n                NULL);\n\n            detail::buildErrHandler(error, __BUILD_PROGRAM_ERR, getBuildInfo<CL_PROGRAM_BUILD_LOG>());\n        }\n\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    /**\n     * Program constructor to allow construction of program from SPIR-V or another IL\n     * for a specific context.\n     * Valid for either OpenCL >= 2.1 or when CL_HPP_USE_IL_KHR is defined.\n     */\n    Program(\n        const Context& context,\n        const vector<char>& IL,\n        bool build = false,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210\n\n        object_ = ::clCreateProgramWithIL(\n            context(), static_cast<const void*>(IL.data()), IL.size(), &error);\n\n#else // #if CL_HPP_TARGET_OPENCL_VERSION >= 210\n\n        typedef clCreateProgramWithILKHR_fn PFN_clCreateProgramWithILKHR;\n        static PFN_clCreateProgramWithILKHR pfn_clCreateProgramWithILKHR = NULL;\n        CL_HPP_INIT_CL_EXT_FCN_PTR_(clCreateProgramWithILKHR);\n\n        return detail::errHandler(\n            pfn_clCreateProgramWithILKHR(\n            context(), static_cast<const void*>(IL.data()), IL.size(), &error);\n\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 210\n\n        detail::errHandler(error, __CREATE_PROGRAM_WITH_IL_ERR);\n\n        if (error == CL_SUCCESS && build) {\n            error = ::clBuildProgram(\n                object_,\n                0,\n                NULL,\n#if !defined(CL_HPP_CL_1_2_DEFAULT_BUILD)\n                \"-cl-std=CL2.0\",\n#else\n                \"\",\n#endif // #if !defined(CL_HPP_CL_1_2_DEFAULT_BUILD)\n                NULL,\n                NULL);\n\n            detail::buildErrHandler(error, __BUILD_PROGRAM_ERR, getBuildInfo<CL_PROGRAM_BUILD_LOG>());\n        }\n\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 210\n\n    /**\n     * Construct a program object from a list of devices and a per-device list of binaries.\n     * \\param context A valid OpenCL context in which to construct the program.\n     * \\param devices A vector of OpenCL device objects for which the program will be created.\n     * \\param binaries A vector of pairs of a pointer to a binary object and its length.\n     * \\param binaryStatus An optional vector that on completion will be resized to\n     *   match the size of binaries and filled with values to specify if each binary\n     *   was successfully loaded.\n     *   Set to CL_SUCCESS if the binary was successfully loaded.\n     *   Set to CL_INVALID_VALUE if the length is 0 or the binary pointer is NULL.\n     *   Set to CL_INVALID_BINARY if the binary provided is not valid for the matching device.\n     * \\param err if non-NULL will be set to CL_SUCCESS on successful operation or one of the following errors:\n     *   CL_INVALID_CONTEXT if context is not a valid context.\n     *   CL_INVALID_VALUE if the length of devices is zero; or if the length of binaries does not match the length of devices; \n     *     or if any entry in binaries is NULL or has length 0.\n     *   CL_INVALID_DEVICE if OpenCL devices listed in devices are not in the list of devices associated with context.\n     *   CL_INVALID_BINARY if an invalid program binary was encountered for any device. binaryStatus will return specific status for each device.\n     *   CL_OUT_OF_HOST_MEMORY if there is a failure to allocate resources required by the OpenCL implementation on the host.\n     */\n    Program(\n        const Context& context,\n        const vector<Device>& devices,\n        const Binaries& binaries,\n        vector<cl_int>* binaryStatus = NULL,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n        \n        const size_type numDevices = devices.size();\n        \n        // Catch size mismatch early and return\n        if(binaries.size() != numDevices) {\n            error = CL_INVALID_VALUE;\n            detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n            return;\n        }\n\n\n        vector<size_type> lengths(numDevices);\n        vector<const unsigned char*> images(numDevices);\n#if !defined(CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY)\n        for (size_type i = 0; i < numDevices; ++i) {\n            images[i] = binaries[i].data();\n            lengths[i] = binaries[(int)i].size();\n        }\n#else // #if !defined(CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY)\n        for (size_type i = 0; i < numDevices; ++i) {\n            images[i] = (const unsigned char*)binaries[i].first;\n            lengths[i] = binaries[(int)i].second;\n        }\n#endif // #if !defined(CL_HPP_ENABLE_PROGRAM_CONSTRUCTION_FROM_ARRAY_COMPATIBILITY)\n        \n        vector<cl_device_id> deviceIDs(numDevices);\n        for( size_type deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) {\n            deviceIDs[deviceIndex] = (devices[deviceIndex])();\n        }\n\n        if(binaryStatus) {\n            binaryStatus->resize(numDevices);\n        }\n        \n        object_ = ::clCreateProgramWithBinary(\n            context(), (cl_uint) devices.size(),\n            deviceIDs.data(),\n            lengths.data(), images.data(), (binaryStatus != NULL && numDevices > 0)\n               ? &binaryStatus->front()\n               : NULL, &error);\n\n        detail::errHandler(error, __CREATE_PROGRAM_WITH_BINARY_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    \n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n    /**\n     * Create program using builtin kernels.\n     * \\param kernelNames Semi-colon separated list of builtin kernel names\n     */\n    Program(\n        const Context& context,\n        const vector<Device>& devices,\n        const string& kernelNames,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n\n        size_type numDevices = devices.size();\n        vector<cl_device_id> deviceIDs(numDevices);\n        for( size_type deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) {\n            deviceIDs[deviceIndex] = (devices[deviceIndex])();\n        }\n        \n        object_ = ::clCreateProgramWithBuiltInKernels(\n            context(), \n            (cl_uint) devices.size(),\n            deviceIDs.data(),\n            kernelNames.c_str(), \n            &error);\n\n        detail::errHandler(error, __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n\n    Program() { }\n    \n\n    /*! \\brief Constructor from cl_program - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     */\n    explicit Program(const cl_program& program, bool retainObject = false) : \n        detail::Wrapper<cl_type>(program, retainObject) { }\n\n    Program& operator = (const cl_program& rhs)\n    {\n        detail::Wrapper<cl_type>::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Program(const Program& program) : detail::Wrapper<cl_type>(program) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    Program& operator = (const Program &program)\n    {\n        detail::Wrapper<cl_type>::operator=(program);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Program(Program&& program) CL_HPP_NOEXCEPT_ : detail::Wrapper<cl_type>(std::move(program)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    Program& operator = (Program &&program)\n    {\n        detail::Wrapper<cl_type>::operator=(std::move(program));\n        return *this;\n    }\n\n    cl_int build(\n        const vector<Device>& devices,\n        const char* options = NULL,\n        void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL,\n        void* data = NULL) const\n    {\n        size_type numDevices = devices.size();\n        vector<cl_device_id> deviceIDs(numDevices);\n        \n        for( size_type deviceIndex = 0; deviceIndex < numDevices; ++deviceIndex ) {\n            deviceIDs[deviceIndex] = (devices[deviceIndex])();\n        }\n\n        cl_int buildError = ::clBuildProgram(\n            object_,\n            (cl_uint)\n            devices.size(),\n            deviceIDs.data(),\n            options,\n            notifyFptr,\n            data);\n\n        return detail::buildErrHandler(buildError, __BUILD_PROGRAM_ERR, getBuildInfo<CL_PROGRAM_BUILD_LOG>());\n    }\n\n    cl_int build(\n        const Device& device,\n        const char* options = NULL,\n        void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL,\n        void* data = NULL) const\n    {\n        cl_device_id deviceID = device();\n\n        cl_int buildError = ::clBuildProgram(\n            object_,\n            1,\n            &deviceID,\n            options,\n            notifyFptr,\n            data);\n\n        BuildLogType buildLog(1);\n        buildLog.push_back(std::make_pair(device, getBuildInfo<CL_PROGRAM_BUILD_LOG>(device)));\n        return detail::buildErrHandler(buildError, __BUILD_PROGRAM_ERR, buildLog);\n    }\n\n    cl_int build(\n        const char* options = NULL,\n        void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL,\n        void* data = NULL) const\n    {\n        cl_int buildError = ::clBuildProgram(\n            object_,\n            0,\n            NULL,\n            options,\n            notifyFptr,\n            data);\n\n        return detail::buildErrHandler(buildError, __BUILD_PROGRAM_ERR, getBuildInfo<CL_PROGRAM_BUILD_LOG>());\n    }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n    cl_int compile(\n        const char* options = NULL,\n        void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL,\n        void* data = NULL) const\n    {\n        cl_int error = ::clCompileProgram(\n            object_,\n            0,\n            NULL,\n            options,\n            0,\n            NULL,\n            NULL,\n            notifyFptr,\n            data);\n        return detail::buildErrHandler(error, __COMPILE_PROGRAM_ERR, getBuildInfo<CL_PROGRAM_BUILD_LOG>());\n    }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n\n    template <typename T>\n    cl_int getInfo(cl_program_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(&::clGetProgramInfo, object_, name, param),\n            __GET_PROGRAM_INFO_ERR);\n    }\n\n    template <cl_program_info name> typename\n    detail::param_traits<detail::cl_program_info, name>::param_type\n    getInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_program_info, name>::param_type param;\n        cl_int result = getInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n\n    template <typename T>\n    cl_int getBuildInfo(\n        const Device& device, cl_program_build_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(\n                &::clGetProgramBuildInfo, object_, device(), name, param),\n                __GET_PROGRAM_BUILD_INFO_ERR);\n    }\n\n    template <cl_program_build_info name> typename\n    detail::param_traits<detail::cl_program_build_info, name>::param_type\n    getBuildInfo(const Device& device, cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_program_build_info, name>::param_type param;\n        cl_int result = getBuildInfo(device, name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n    \n    /**\n     * Build info function that returns a vector of device/info pairs for the specified \n     * info type and for all devices in the program.\n     * On an error reading the info for any device, an empty vector of info will be returned.\n     */\n    template <cl_program_build_info name>\n    vector<std::pair<cl::Device, typename detail::param_traits<detail::cl_program_build_info, name>::param_type>>\n        getBuildInfo(cl_int *err = NULL) const\n    {\n        cl_int result = CL_SUCCESS;\n\n        auto devs = getInfo<CL_PROGRAM_DEVICES>(&result);\n        vector<std::pair<cl::Device, typename detail::param_traits<detail::cl_program_build_info, name>::param_type>>\n            devInfo;\n\n        // If there was an initial error from getInfo return the error\n        if (result != CL_SUCCESS) {\n            if (err != NULL) {\n                *err = result;\n            }\n            return devInfo;\n        }\n\n        for (const cl::Device &d : devs) {\n            typename detail::param_traits<\n                detail::cl_program_build_info, name>::param_type param;\n            result = getBuildInfo(d, name, &param);\n            devInfo.push_back(\n                std::pair<cl::Device, typename detail::param_traits<detail::cl_program_build_info, name>::param_type>\n                (d, param));\n            if (result != CL_SUCCESS) {\n                // On error, leave the loop and return the error code\n                break;\n            }\n        }\n        if (err != NULL) {\n            *err = result;\n        }\n        if (result != CL_SUCCESS) {\n            devInfo.clear();\n        }\n        return devInfo;\n    }\n\n    cl_int createKernels(vector<Kernel>* kernels)\n    {\n        cl_uint numKernels;\n        cl_int err = ::clCreateKernelsInProgram(object_, 0, NULL, &numKernels);\n        if (err != CL_SUCCESS) {\n            return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR);\n        }\n\n        vector<cl_kernel> value(numKernels);\n        \n        err = ::clCreateKernelsInProgram(\n            object_, numKernels, value.data(), NULL);\n        if (err != CL_SUCCESS) {\n            return detail::errHandler(err, __CREATE_KERNELS_IN_PROGRAM_ERR);\n        }\n\n        if (kernels) {\n            kernels->resize(value.size());\n\n            // Assign to param, constructing with retain behaviour\n            // to correctly capture each underlying CL object\n            for (size_type i = 0; i < value.size(); i++) {\n                // We do not need to retain because this kernel is being created \n                // by the runtime\n                (*kernels)[i] = Kernel(value[i], false);\n            }\n        }\n        return CL_SUCCESS;\n    }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 220\n#if defined(CL_USE_DEPRECATED_OPENCL_2_2_APIS)\n    /*! \\brief Registers a callback function to be called when destructors for\n     *         program scope global variables are complete and before the\n     *         program is released.\n     *\n     *  Wraps clSetProgramReleaseCallback().\n     *\n     *  Each call to this function registers the specified user callback function\n     *  on a callback stack associated with program. The registered user callback\n     *  functions are called in the reverse order in which they were registered.\n     */\n    CL_API_PREFIX__VERSION_2_2_DEPRECATED cl_int setReleaseCallback(\n        void (CL_CALLBACK * pfn_notify)(cl_program program, void * user_data),\n        void * user_data = NULL) CL_API_SUFFIX__VERSION_2_2_DEPRECATED\n    {\n        return detail::errHandler(\n            ::clSetProgramReleaseCallback(\n                object_,\n                pfn_notify,\n                user_data),\n            __SET_PROGRAM_RELEASE_CALLBACK_ERR);\n    }\n#endif // #if defined(CL_USE_DEPRECATED_OPENCL_2_2_APIS)\n\n    /*! \\brief Sets a SPIR-V specialization constant.\n     *\n     *  Wraps clSetProgramSpecializationConstant().\n     */\n    template <typename T>\n    typename std::enable_if<!std::is_pointer<T>::value, cl_int>::type\n        setSpecializationConstant(cl_uint index, const T &value)\n    {\n        return detail::errHandler(\n            ::clSetProgramSpecializationConstant(\n                object_,\n                index,\n                sizeof(value),\n                &value),\n            __SET_PROGRAM_SPECIALIZATION_CONSTANT_ERR);\n    }\n\n    /*! \\brief Sets a SPIR-V specialization constant.\n     *\n     *  Wraps clSetProgramSpecializationConstant().\n     */\n    cl_int setSpecializationConstant(cl_uint index, size_type size, const void* value)\n    {\n        return detail::errHandler(\n            ::clSetProgramSpecializationConstant(\n                object_,\n                index,\n                size,\n                value),\n            __SET_PROGRAM_SPECIALIZATION_CONSTANT_ERR);\n    }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 220\n};\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\ninline Program linkProgram(\n    Program input1,\n    Program input2,\n    const char* options = NULL,\n    void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL,\n    void* data = NULL,\n    cl_int* err = NULL) \n{\n    cl_int error_local = CL_SUCCESS;\n\n    cl_program programs[2] = { input1(), input2() };\n\n    Context ctx = input1.getInfo<CL_PROGRAM_CONTEXT>(&error_local);\n    if(error_local!=CL_SUCCESS) {\n        detail::errHandler(error_local, __LINK_PROGRAM_ERR);\n    }\n\n    cl_program prog = ::clLinkProgram(\n        ctx(),\n        0,\n        NULL,\n        options,\n        2,\n        programs,\n        notifyFptr,\n        data,\n        &error_local);\n\n    detail::errHandler(error_local,__COMPILE_PROGRAM_ERR);\n    if (err != NULL) {\n        *err = error_local;\n    }\n\n    return Program(prog);\n}\n\ninline Program linkProgram(\n    vector<Program> inputPrograms,\n    const char* options = NULL,\n    void (CL_CALLBACK * notifyFptr)(cl_program, void *) = NULL,\n    void* data = NULL,\n    cl_int* err = NULL) \n{\n    cl_int error_local = CL_SUCCESS;\n\n    vector<cl_program> programs(inputPrograms.size());\n\n    for (unsigned int i = 0; i < inputPrograms.size(); i++) {\n        programs[i] = inputPrograms[i]();\n    }\n    \n    Context ctx;\n    if(inputPrograms.size() > 0) {\n        ctx = inputPrograms[0].getInfo<CL_PROGRAM_CONTEXT>(&error_local);\n        if(error_local!=CL_SUCCESS) {\n            detail::errHandler(error_local, __LINK_PROGRAM_ERR);\n        }\n    }\n    cl_program prog = ::clLinkProgram(\n        ctx(),\n        0,\n        NULL,\n        options,\n        (cl_uint)inputPrograms.size(),\n        programs.data(),\n        notifyFptr,\n        data,\n        &error_local);\n\n    detail::errHandler(error_local,__COMPILE_PROGRAM_ERR);\n    if (err != NULL) {\n        *err = error_local;\n    }\n\n    return Program(prog, false);\n}\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n\n// Template specialization for CL_PROGRAM_BINARIES\ntemplate <>\ninline cl_int cl::Program::getInfo(cl_program_info name, vector<vector<unsigned char>>* param) const\n{\n    if (name != CL_PROGRAM_BINARIES) {\n        return CL_INVALID_VALUE;\n    }\n    if (param) {\n        // Resize the parameter array appropriately for each allocation\n        // and pass down to the helper\n\n        vector<size_type> sizes = getInfo<CL_PROGRAM_BINARY_SIZES>();\n        size_type numBinaries = sizes.size();\n\n        // Resize the parameter array and constituent arrays\n        param->resize(numBinaries);\n        for (size_type i = 0; i < numBinaries; ++i) {\n            (*param)[i].resize(sizes[i]);\n        }\n\n        return detail::errHandler(\n            detail::getInfo(&::clGetProgramInfo, object_, name, param),\n            __GET_PROGRAM_INFO_ERR);\n    }\n\n    return CL_SUCCESS;\n}\n\ntemplate<>\ninline vector<vector<unsigned char>> cl::Program::getInfo<CL_PROGRAM_BINARIES>(cl_int* err) const\n{\n    vector<vector<unsigned char>> binariesVectors;\n\n    cl_int result = getInfo(CL_PROGRAM_BINARIES, &binariesVectors);\n    if (err != NULL) {\n        *err = result;\n    }\n    return binariesVectors;\n}\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 220\n// Template specialization for clSetProgramSpecializationConstant\ntemplate <>\ninline cl_int cl::Program::setSpecializationConstant(cl_uint index, const bool &value)\n{\n    cl_uchar ucValue = value ? CL_UCHAR_MAX : 0;\n    return detail::errHandler(\n        ::clSetProgramSpecializationConstant(\n            object_,\n            index,\n            sizeof(ucValue),\n            &ucValue),\n        __SET_PROGRAM_SPECIALIZATION_CONSTANT_ERR);\n}\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 220\n\ninline Kernel::Kernel(const Program& program, const char* name, cl_int* err)\n{\n    cl_int error;\n\n    object_ = ::clCreateKernel(program(), name, &error);\n    detail::errHandler(error, __CREATE_KERNEL_ERR);\n\n    if (err != NULL) {\n        *err = error;\n    }\n\n}\n\nenum class QueueProperties : cl_command_queue_properties\n{\n    None = 0,\n    Profiling = CL_QUEUE_PROFILING_ENABLE,\n    OutOfOrder = CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE,\n};\n\ninline QueueProperties operator|(QueueProperties lhs, QueueProperties rhs)\n{\n    return static_cast<QueueProperties>(static_cast<cl_command_queue_properties>(lhs) | static_cast<cl_command_queue_properties>(rhs));\n}\n\n/*! \\class CommandQueue\n * \\brief CommandQueue interface for cl_command_queue.\n */\nclass CommandQueue : public detail::Wrapper<cl_command_queue>\n{\nprivate:\n    static std::once_flag default_initialized_;\n    static CommandQueue default_;\n    static cl_int default_error_;\n\n    /*! \\brief Create the default command queue returned by @ref getDefault.\n     *\n     * It sets default_error_ to indicate success or failure. It does not throw\n     * @c cl::Error.\n     */\n    static void makeDefault()\n    {\n        /* We don't want to throw an error from this function, so we have to\n         * catch and set the error flag.\n         */\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n        try\n#endif\n        {\n            int error;\n            Context context = Context::getDefault(&error);\n\n            if (error != CL_SUCCESS) {\n                default_error_ = error;\n            }\n            else {\n                Device device = Device::getDefault();\n                default_ = CommandQueue(context, device, 0, &default_error_);\n            }\n        }\n#if defined(CL_HPP_ENABLE_EXCEPTIONS)\n        catch (cl::Error &e) {\n            default_error_ = e.err();\n        }\n#endif\n    }\n\n    /*! \\brief Create the default command queue.\n     *\n     * This sets @c default_. It does not throw\n     * @c cl::Error.\n     */\n    static void makeDefaultProvided(const CommandQueue &c) {\n        default_ = c;\n    }\n\npublic:\n#ifdef CL_HPP_UNIT_TEST_ENABLE\n    /*! \\brief Reset the default.\n    *\n    * This sets @c default_ to an empty value to support cleanup in\n    * the unit test framework.\n    * This function is not thread safe.\n    */\n    static void unitTestClearDefault() {\n        default_ = CommandQueue();\n    }\n#endif // #ifdef CL_HPP_UNIT_TEST_ENABLE\n        \n\n    /*!\n     * \\brief Constructs a CommandQueue based on passed properties.\n     * Will return an CL_INVALID_QUEUE_PROPERTIES error if CL_QUEUE_ON_DEVICE is specified.\n     */\n   CommandQueue(\n        cl_command_queue_properties properties,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        Context context = Context::getDefault(&error);\n        detail::errHandler(error, __CREATE_CONTEXT_ERR);\n\n        if (error != CL_SUCCESS) {\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n        else {\n            Device device = context.getInfo<CL_CONTEXT_DEVICES>()[0];\n            bool useWithProperties;\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200 && CL_HPP_MINIMUM_OPENCL_VERSION < 200\n            // Run-time decision based on the actual platform\n            {\n                cl_uint version = detail::getContextPlatformVersion(context());\n                useWithProperties = (version >= 0x20000); // OpenCL 2.0 or above\n            }\n#elif CL_HPP_TARGET_OPENCL_VERSION >= 200\n            useWithProperties = true;\n#else\n            useWithProperties = false;\n#endif\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n            if (useWithProperties) {\n                cl_queue_properties queue_properties[] = {\n                    CL_QUEUE_PROPERTIES, properties, 0 };\n                if ((properties & CL_QUEUE_ON_DEVICE) == 0) {\n                    object_ = ::clCreateCommandQueueWithProperties(\n                        context(), device(), queue_properties, &error);\n                }\n                else {\n                    error = CL_INVALID_QUEUE_PROPERTIES;\n                }\n\n                detail::errHandler(error, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n                if (err != NULL) {\n                    *err = error;\n                }\n            }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 200\n#if CL_HPP_MINIMUM_OPENCL_VERSION < 200\n            if (!useWithProperties) {\n                object_ = ::clCreateCommandQueue(\n                    context(), device(), properties, &error);\n\n                detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR);\n                if (err != NULL) {\n                    *err = error;\n                }\n            }\n#endif // CL_HPP_MINIMUM_OPENCL_VERSION < 200\n        }\n    }\n\n   /*!\n    * \\brief Constructs a CommandQueue based on passed properties.\n    * Will return an CL_INVALID_QUEUE_PROPERTIES error if CL_QUEUE_ON_DEVICE is specified.\n    */\n   CommandQueue(\n       QueueProperties properties,\n       cl_int* err = NULL)\n   {\n       cl_int error;\n\n       Context context = Context::getDefault(&error);\n       detail::errHandler(error, __CREATE_CONTEXT_ERR);\n\n       if (error != CL_SUCCESS) {\n           if (err != NULL) {\n               *err = error;\n           }\n       }\n       else {\n           Device device = context.getInfo<CL_CONTEXT_DEVICES>()[0];\n           bool useWithProperties;\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200 && CL_HPP_MINIMUM_OPENCL_VERSION < 200\n           // Run-time decision based on the actual platform\n           {\n               cl_uint version = detail::getContextPlatformVersion(context());\n               useWithProperties = (version >= 0x20000); // OpenCL 2.0 or above\n           }\n#elif CL_HPP_TARGET_OPENCL_VERSION >= 200\n           useWithProperties = true;\n#else\n           useWithProperties = false;\n#endif\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n           if (useWithProperties) {\n               cl_queue_properties queue_properties[] = {\n                   CL_QUEUE_PROPERTIES, static_cast<cl_queue_properties>(properties), 0 };\n\n               object_ = ::clCreateCommandQueueWithProperties(\n                   context(), device(), queue_properties, &error);\n\n               detail::errHandler(error, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n               if (err != NULL) {\n                   *err = error;\n               }\n           }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 200\n#if CL_HPP_MINIMUM_OPENCL_VERSION < 200\n           if (!useWithProperties) {\n               object_ = ::clCreateCommandQueue(\n                   context(), device(), static_cast<cl_command_queue_properties>(properties), &error);\n\n               detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR);\n               if (err != NULL) {\n                   *err = error;\n               }\n           }\n#endif // CL_HPP_MINIMUM_OPENCL_VERSION < 200\n\n       }\n   }\n\n    /*!\n     * \\brief Constructs a CommandQueue for an implementation defined device in the given context\n     * Will return an CL_INVALID_QUEUE_PROPERTIES error if CL_QUEUE_ON_DEVICE is specified.\n     */\n    explicit CommandQueue(\n        const Context& context,\n        cl_command_queue_properties properties = 0,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n        bool useWithProperties;\n        vector<cl::Device> devices;\n        error = context.getInfo(CL_CONTEXT_DEVICES, &devices);\n\n        detail::errHandler(error, __CREATE_CONTEXT_ERR);\n\n        if (error != CL_SUCCESS)\n        {\n            if (err != NULL) {\n                *err = error;\n            }\n            return;\n        }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200 && CL_HPP_MINIMUM_OPENCL_VERSION < 200\n        // Run-time decision based on the actual platform\n        {\n            cl_uint version = detail::getContextPlatformVersion(context());\n            useWithProperties = (version >= 0x20000); // OpenCL 2.0 or above\n        }\n#elif CL_HPP_TARGET_OPENCL_VERSION >= 200\n        useWithProperties = true;\n#else\n        useWithProperties = false;\n#endif\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n        if (useWithProperties) {\n            cl_queue_properties queue_properties[] = {\n                CL_QUEUE_PROPERTIES, properties, 0 };\n            if ((properties & CL_QUEUE_ON_DEVICE) == 0) {\n                object_ = ::clCreateCommandQueueWithProperties(\n                    context(), devices[0](), queue_properties, &error);\n            }\n            else {\n                error = CL_INVALID_QUEUE_PROPERTIES;\n            }\n\n            detail::errHandler(error, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 200\n#if CL_HPP_MINIMUM_OPENCL_VERSION < 200\n        if (!useWithProperties) {\n            object_ = ::clCreateCommandQueue(\n                context(), devices[0](), properties, &error);\n\n            detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n#endif // CL_HPP_MINIMUM_OPENCL_VERSION < 200\n    }\n\n    /*!\n    * \\brief Constructs a CommandQueue for an implementation defined device in the given context\n    * Will return an CL_INVALID_QUEUE_PROPERTIES error if CL_QUEUE_ON_DEVICE is specified.\n    */\n    explicit CommandQueue(\n        const Context& context,\n        QueueProperties properties,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n        bool useWithProperties;\n        vector<cl::Device> devices;\n        error = context.getInfo(CL_CONTEXT_DEVICES, &devices);\n\n        detail::errHandler(error, __CREATE_CONTEXT_ERR);\n\n        if (error != CL_SUCCESS)\n        {\n            if (err != NULL) {\n                *err = error;\n            }\n            return;\n        }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200 && CL_HPP_MINIMUM_OPENCL_VERSION < 200\n        // Run-time decision based on the actual platform\n        {\n            cl_uint version = detail::getContextPlatformVersion(context());\n            useWithProperties = (version >= 0x20000); // OpenCL 2.0 or above\n        }\n#elif CL_HPP_TARGET_OPENCL_VERSION >= 200\n        useWithProperties = true;\n#else\n        useWithProperties = false;\n#endif\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n        if (useWithProperties) {\n            cl_queue_properties queue_properties[] = {\n                CL_QUEUE_PROPERTIES, static_cast<cl_queue_properties>(properties), 0 };\n            object_ = ::clCreateCommandQueueWithProperties(\n                context(), devices[0](), queue_properties, &error);\n\n            detail::errHandler(error, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 200\n#if CL_HPP_MINIMUM_OPENCL_VERSION < 200\n        if (!useWithProperties) {\n            object_ = ::clCreateCommandQueue(\n                context(), devices[0](), static_cast<cl_command_queue_properties>(properties), &error);\n\n            detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n#endif // CL_HPP_MINIMUM_OPENCL_VERSION < 200\n    }\n\n    /*!\n     * \\brief Constructs a CommandQueue for a passed device and context\n     * Will return an CL_INVALID_QUEUE_PROPERTIES error if CL_QUEUE_ON_DEVICE is specified.\n     */\n    CommandQueue(\n        const Context& context,\n        const Device& device,\n        cl_command_queue_properties properties = 0,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n        bool useWithProperties;\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200 && CL_HPP_MINIMUM_OPENCL_VERSION < 200\n        // Run-time decision based on the actual platform\n        {\n            cl_uint version = detail::getContextPlatformVersion(context());\n            useWithProperties = (version >= 0x20000); // OpenCL 2.0 or above\n        }\n#elif CL_HPP_TARGET_OPENCL_VERSION >= 200\n        useWithProperties = true;\n#else\n        useWithProperties = false;\n#endif\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n        if (useWithProperties) {\n            cl_queue_properties queue_properties[] = {\n                CL_QUEUE_PROPERTIES, properties, 0 };\n            object_ = ::clCreateCommandQueueWithProperties(\n                context(), device(), queue_properties, &error);\n\n            detail::errHandler(error, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 200\n#if CL_HPP_MINIMUM_OPENCL_VERSION < 200\n        if (!useWithProperties) {\n            object_ = ::clCreateCommandQueue(\n                context(), device(), properties, &error);\n\n            detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n#endif // CL_HPP_MINIMUM_OPENCL_VERSION < 200\n    }\n\n    /*!\n     * \\brief Constructs a CommandQueue for a passed device and context\n     * Will return an CL_INVALID_QUEUE_PROPERTIES error if CL_QUEUE_ON_DEVICE is specified.\n     */\n    CommandQueue(\n        const Context& context,\n        const Device& device,\n        QueueProperties properties,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n        bool useWithProperties;\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200 && CL_HPP_MINIMUM_OPENCL_VERSION < 200\n        // Run-time decision based on the actual platform\n        {\n            cl_uint version = detail::getContextPlatformVersion(context());\n            useWithProperties = (version >= 0x20000); // OpenCL 2.0 or above\n        }\n#elif CL_HPP_TARGET_OPENCL_VERSION >= 200\n        useWithProperties = true;\n#else\n        useWithProperties = false;\n#endif\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n        if (useWithProperties) {\n            cl_queue_properties queue_properties[] = {\n                CL_QUEUE_PROPERTIES, static_cast<cl_queue_properties>(properties), 0 };\n            object_ = ::clCreateCommandQueueWithProperties(\n                context(), device(), queue_properties, &error);\n\n            detail::errHandler(error, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 200\n#if CL_HPP_MINIMUM_OPENCL_VERSION < 200\n        if (!useWithProperties) {\n            object_ = ::clCreateCommandQueue(\n                context(), device(), static_cast<cl_command_queue_properties>(properties), &error);\n\n            detail::errHandler(error, __CREATE_COMMAND_QUEUE_ERR);\n            if (err != NULL) {\n                *err = error;\n            }\n        }\n#endif // CL_HPP_MINIMUM_OPENCL_VERSION < 200\n    }\n\n    static CommandQueue getDefault(cl_int * err = NULL) \n    {\n        std::call_once(default_initialized_, makeDefault);\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n        detail::errHandler(default_error_, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n#else // CL_HPP_TARGET_OPENCL_VERSION >= 200\n        detail::errHandler(default_error_, __CREATE_COMMAND_QUEUE_ERR);\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 200\n        if (err != NULL) {\n            *err = default_error_;\n        }\n        return default_;\n    }\n\n    /**\n     * Modify the default command queue to be used by\n     * subsequent operations.\n     * Will only set the default if no default was previously created.\n     * @return updated default command queue.\n     *         Should be compared to the passed value to ensure that it was updated.\n     */\n    static CommandQueue setDefault(const CommandQueue &default_queue)\n    {\n        std::call_once(default_initialized_, makeDefaultProvided, std::cref(default_queue));\n        detail::errHandler(default_error_);\n        return default_;\n    }\n\n    CommandQueue() { }\n\n\n    /*! \\brief Constructor from cl_command_queue - takes ownership.\n     *\n     * \\param retainObject will cause the constructor to retain its cl object.\n     *                     Defaults to false to maintain compatibility with\n     *                     earlier versions.\n     */\n    explicit CommandQueue(const cl_command_queue& commandQueue, bool retainObject = false) : \n        detail::Wrapper<cl_type>(commandQueue, retainObject) { }\n\n    CommandQueue& operator = (const cl_command_queue& rhs)\n    {\n        detail::Wrapper<cl_type>::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    CommandQueue(const CommandQueue& queue) : detail::Wrapper<cl_type>(queue) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    CommandQueue& operator = (const CommandQueue &queue)\n    {\n        detail::Wrapper<cl_type>::operator=(queue);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    CommandQueue(CommandQueue&& queue) CL_HPP_NOEXCEPT_ : detail::Wrapper<cl_type>(std::move(queue)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    CommandQueue& operator = (CommandQueue &&queue)\n    {\n        detail::Wrapper<cl_type>::operator=(std::move(queue));\n        return *this;\n    }\n\n    template <typename T>\n    cl_int getInfo(cl_command_queue_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(\n                &::clGetCommandQueueInfo, object_, name, param),\n                __GET_COMMAND_QUEUE_INFO_ERR);\n    }\n\n    template <cl_command_queue_info name> typename\n    detail::param_traits<detail::cl_command_queue_info, name>::param_type\n    getInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_command_queue_info, name>::param_type param;\n        cl_int result = getInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n\n    cl_int enqueueReadBuffer(\n        const Buffer& buffer,\n        cl_bool blocking,\n        size_type offset,\n        size_type size,\n        void* ptr,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueReadBuffer(\n                object_, buffer(), blocking, offset, size,\n                ptr,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_READ_BUFFER_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    cl_int enqueueWriteBuffer(\n        const Buffer& buffer,\n        cl_bool blocking,\n        size_type offset,\n        size_type size,\n        const void* ptr,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueWriteBuffer(\n                object_, buffer(), blocking, offset, size,\n                ptr,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n                __ENQUEUE_WRITE_BUFFER_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    cl_int enqueueCopyBuffer(\n        const Buffer& src,\n        const Buffer& dst,\n        size_type src_offset,\n        size_type dst_offset,\n        size_type size,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueCopyBuffer(\n                object_, src(), dst(), src_offset, dst_offset, size,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQEUE_COPY_BUFFER_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n#if CL_HPP_TARGET_OPENCL_VERSION >= 110\n    cl_int enqueueReadBufferRect(\n        const Buffer& buffer,\n        cl_bool blocking,\n        const array<size_type, 3>& buffer_offset,\n        const array<size_type, 3>& host_offset,\n        const array<size_type, 3>& region,\n        size_type buffer_row_pitch,\n        size_type buffer_slice_pitch,\n        size_type host_row_pitch,\n        size_type host_slice_pitch,\n        void *ptr,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueReadBufferRect(\n                object_, \n                buffer(), \n                blocking,\n                buffer_offset.data(),\n                host_offset.data(),\n                region.data(),\n                buffer_row_pitch,\n                buffer_slice_pitch,\n                host_row_pitch,\n                host_slice_pitch,\n                ptr,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n                __ENQUEUE_READ_BUFFER_RECT_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    cl_int enqueueWriteBufferRect(\n        const Buffer& buffer,\n        cl_bool blocking,\n        const array<size_type, 3>& buffer_offset,\n        const array<size_type, 3>& host_offset,\n        const array<size_type, 3>& region,\n        size_type buffer_row_pitch,\n        size_type buffer_slice_pitch,\n        size_type host_row_pitch,\n        size_type host_slice_pitch,\n        const void *ptr,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueWriteBufferRect(\n                object_, \n                buffer(), \n                blocking,\n                buffer_offset.data(),\n                host_offset.data(),\n                region.data(),\n                buffer_row_pitch,\n                buffer_slice_pitch,\n                host_row_pitch,\n                host_slice_pitch,\n                ptr,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n                __ENQUEUE_WRITE_BUFFER_RECT_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    cl_int enqueueCopyBufferRect(\n        const Buffer& src,\n        const Buffer& dst,\n        const array<size_type, 3>& src_origin,\n        const array<size_type, 3>& dst_origin,\n        const array<size_type, 3>& region,\n        size_type src_row_pitch,\n        size_type src_slice_pitch,\n        size_type dst_row_pitch,\n        size_type dst_slice_pitch,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueCopyBufferRect(\n                object_, \n                src(), \n                dst(), \n                src_origin.data(),\n                dst_origin.data(),\n                region.data(),\n                src_row_pitch,\n                src_slice_pitch,\n                dst_row_pitch,\n                dst_slice_pitch,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQEUE_COPY_BUFFER_RECT_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 110\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n    /**\n     * Enqueue a command to fill a buffer object with a pattern\n     * of a given size. The pattern is specified as a vector type.\n     * \\tparam PatternType The datatype of the pattern field. \n     *     The pattern type must be an accepted OpenCL data type.\n     * \\tparam offset Is the offset in bytes into the buffer at \n     *     which to start filling. This must be a multiple of \n     *     the pattern size.\n     * \\tparam size Is the size in bytes of the region to fill.\n     *     This must be a multiple of the pattern size.\n     */\n    template<typename PatternType>\n    cl_int enqueueFillBuffer(\n        const Buffer& buffer,\n        PatternType pattern,\n        size_type offset,\n        size_type size,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueFillBuffer(\n                object_, \n                buffer(),\n                static_cast<void*>(&pattern),\n                sizeof(PatternType), \n                offset, \n                size,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n                __ENQUEUE_FILL_BUFFER_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n\n    cl_int enqueueReadImage(\n        const Image& image,\n        cl_bool blocking,\n        const array<size_type, 3>& origin,\n        const array<size_type, 3>& region,\n        size_type row_pitch,\n        size_type slice_pitch,\n        void* ptr,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueReadImage(\n                object_, \n                image(), \n                blocking, \n                origin.data(),\n                region.data(), \n                row_pitch, \n                slice_pitch, \n                ptr,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_READ_IMAGE_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    cl_int enqueueWriteImage(\n        const Image& image,\n        cl_bool blocking,\n        const array<size_type, 3>& origin,\n        const array<size_type, 3>& region,\n        size_type row_pitch,\n        size_type slice_pitch,\n        const void* ptr,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueWriteImage(\n                object_, \n                image(), \n                blocking, \n                origin.data(),\n                region.data(), \n                row_pitch, \n                slice_pitch, \n                ptr,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_WRITE_IMAGE_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    cl_int enqueueCopyImage(\n        const Image& src,\n        const Image& dst,\n        const array<size_type, 3>& src_origin,\n        const array<size_type, 3>& dst_origin,\n        const array<size_type, 3>& region,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueCopyImage(\n                object_, \n                src(), \n                dst(), \n                src_origin.data(),\n                dst_origin.data(), \n                region.data(),\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_COPY_IMAGE_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n    /**\n     * Enqueue a command to fill an image object with a specified color.\n     * \\param fillColor is the color to use to fill the image.\n     *     This is a four component RGBA floating-point color value if\n     *     the image channel data type is not an unnormalized signed or\n     *     unsigned data type.\n     */\n    cl_int enqueueFillImage(\n        const Image& image,\n        cl_float4 fillColor,\n        const array<size_type, 3>& origin,\n        const array<size_type, 3>& region,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueFillImage(\n                object_, \n                image(),\n                static_cast<void*>(&fillColor), \n                origin.data(),\n                region.data(),\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n                __ENQUEUE_FILL_IMAGE_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    /**\n     * Enqueue a command to fill an image object with a specified color.\n     * \\param fillColor is the color to use to fill the image.\n     *     This is a four component RGBA signed integer color value if\n     *     the image channel data type is an unnormalized signed integer\n     *     type.\n     */\n    cl_int enqueueFillImage(\n        const Image& image,\n        cl_int4 fillColor,\n        const array<size_type, 3>& origin,\n        const array<size_type, 3>& region,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueFillImage(\n                object_, \n                image(),\n                static_cast<void*>(&fillColor), \n                origin.data(),\n                region.data(),\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n                __ENQUEUE_FILL_IMAGE_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    /**\n     * Enqueue a command to fill an image object with a specified color.\n     * \\param fillColor is the color to use to fill the image.\n     *     This is a four component RGBA unsigned integer color value if\n     *     the image channel data type is an unnormalized unsigned integer\n     *     type.\n     */\n    cl_int enqueueFillImage(\n        const Image& image,\n        cl_uint4 fillColor,\n        const array<size_type, 3>& origin,\n        const array<size_type, 3>& region,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueFillImage(\n                object_, \n                image(),\n                static_cast<void*>(&fillColor), \n                origin.data(),\n                region.data(),\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n                __ENQUEUE_FILL_IMAGE_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n\n    cl_int enqueueCopyImageToBuffer(\n        const Image& src,\n        const Buffer& dst,\n        const array<size_type, 3>& src_origin,\n        const array<size_type, 3>& region,\n        size_type dst_offset,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueCopyImageToBuffer(\n                object_, \n                src(), \n                dst(), \n                src_origin.data(),\n                region.data(), \n                dst_offset,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    cl_int enqueueCopyBufferToImage(\n        const Buffer& src,\n        const Image& dst,\n        size_type src_offset,\n        const array<size_type, 3>& dst_origin,\n        const array<size_type, 3>& region,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueCopyBufferToImage(\n                object_, \n                src(), \n                dst(), \n                src_offset,\n                dst_origin.data(), \n                region.data(),\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    void* enqueueMapBuffer(\n        const Buffer& buffer,\n        cl_bool blocking,\n        cl_map_flags flags,\n        size_type offset,\n        size_type size,\n        const vector<Event>* events = NULL,\n        Event* event = NULL,\n        cl_int* err = NULL) const\n    {\n        cl_event tmp;\n        cl_int error;\n        void * result = ::clEnqueueMapBuffer(\n            object_, buffer(), blocking, flags, offset, size,\n            (events != NULL) ? (cl_uint) events->size() : 0,\n            (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n            (event != NULL) ? &tmp : NULL,\n            &error);\n\n        detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n        if (event != NULL && error == CL_SUCCESS)\n            *event = tmp;\n\n        return result;\n    }\n\n    void* enqueueMapImage(\n        const Image& buffer,\n        cl_bool blocking,\n        cl_map_flags flags,\n        const array<size_type, 3>& origin,\n        const array<size_type, 3>& region,\n        size_type * row_pitch,\n        size_type * slice_pitch,\n        const vector<Event>* events = NULL,\n        Event* event = NULL,\n        cl_int* err = NULL) const\n    {\n        cl_event tmp;\n        cl_int error;\n        void * result = ::clEnqueueMapImage(\n            object_, buffer(), blocking, flags,\n            origin.data(), \n            region.data(),\n            row_pitch, slice_pitch,\n            (events != NULL) ? (cl_uint) events->size() : 0,\n            (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n            (event != NULL) ? &tmp : NULL,\n            &error);\n\n        detail::errHandler(error, __ENQUEUE_MAP_IMAGE_ERR);\n        if (err != NULL) {\n              *err = error;\n        }\n        if (event != NULL && error == CL_SUCCESS)\n            *event = tmp;\n        return result;\n    }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n    /**\n     * Enqueues a command that will allow the host to update a region of a coarse-grained SVM buffer.\n     * This variant takes a raw SVM pointer.\n     */\n    template<typename T>\n    cl_int enqueueMapSVM(\n        T* ptr,\n        cl_bool blocking,\n        cl_map_flags flags,\n        size_type size,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(::clEnqueueSVMMap(\n            object_, blocking, flags, static_cast<void*>(ptr), size,\n            (events != NULL) ? (cl_uint)events->size() : 0,\n            (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL,\n            (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_MAP_BUFFER_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n\n    /**\n     * Enqueues a command that will allow the host to update a region of a coarse-grained SVM buffer.\n     * This variant takes a cl::pointer instance.\n     */\n    template<typename T, class D>\n    cl_int enqueueMapSVM(\n        cl::pointer<T, D> &ptr,\n        cl_bool blocking,\n        cl_map_flags flags,\n        size_type size,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(::clEnqueueSVMMap(\n            object_, blocking, flags, static_cast<void*>(ptr.get()), size,\n            (events != NULL) ? (cl_uint)events->size() : 0,\n            (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL,\n            (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_MAP_BUFFER_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    /**\n     * Enqueues a command that will allow the host to update a region of a coarse-grained SVM buffer.\n     * This variant takes a cl::vector instance.\n     */\n    template<typename T, class Alloc>\n    cl_int enqueueMapSVM(\n        cl::vector<T, Alloc> &container,\n        cl_bool blocking,\n        cl_map_flags flags,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(::clEnqueueSVMMap(\n            object_, blocking, flags, static_cast<void*>(container.data()), container.size()*sizeof(T),\n            (events != NULL) ? (cl_uint)events->size() : 0,\n            (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL,\n            (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_MAP_BUFFER_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\n    cl_int enqueueUnmapMemObject(\n        const Memory& memory,\n        void* mapped_ptr,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueUnmapMemObject(\n                object_, memory(), mapped_ptr,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_UNMAP_MEM_OBJECT_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n    /**\n     * Enqueues a command that will release a coarse-grained SVM buffer back to the OpenCL runtime.\n     * This variant takes a raw SVM pointer.\n     */\n    template<typename T>\n    cl_int enqueueUnmapSVM(\n        T* ptr,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueSVMUnmap(\n            object_, static_cast<void*>(ptr),\n            (events != NULL) ? (cl_uint)events->size() : 0,\n            (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL,\n            (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_UNMAP_MEM_OBJECT_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    /**\n     * Enqueues a command that will release a coarse-grained SVM buffer back to the OpenCL runtime.\n     * This variant takes a cl::pointer instance.\n     */\n    template<typename T, class D>\n    cl_int enqueueUnmapSVM(\n        cl::pointer<T, D> &ptr,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueSVMUnmap(\n            object_, static_cast<void*>(ptr.get()),\n            (events != NULL) ? (cl_uint)events->size() : 0,\n            (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL,\n            (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_UNMAP_MEM_OBJECT_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    /**\n     * Enqueues a command that will release a coarse-grained SVM buffer back to the OpenCL runtime.\n     * This variant takes a cl::vector instance.\n     */\n    template<typename T, class Alloc>\n    cl_int enqueueUnmapSVM(\n        cl::vector<T, Alloc> &container,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueSVMUnmap(\n            object_, static_cast<void*>(container.data()),\n            (events != NULL) ? (cl_uint)events->size() : 0,\n            (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL,\n            (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_UNMAP_MEM_OBJECT_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n    /**\n     * Enqueues a marker command which waits for either a list of events to complete, \n     * or all previously enqueued commands to complete.\n     *\n     * Enqueues a marker command which waits for either a list of events to complete, \n     * or if the list is empty it waits for all commands previously enqueued in command_queue \n     * to complete before it completes. This command returns an event which can be waited on, \n     * i.e. this event can be waited on to insure that all events either in the event_wait_list \n     * or all previously enqueued commands, queued before this command to command_queue, \n     * have completed.\n     */\n    cl_int enqueueMarkerWithWaitList(\n        const vector<Event> *events = 0,\n        Event *event = 0) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueMarkerWithWaitList(\n                object_,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_MARKER_WAIT_LIST_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    /**\n     * A synchronization point that enqueues a barrier operation.\n     *\n     * Enqueues a barrier command which waits for either a list of events to complete, \n     * or if the list is empty it waits for all commands previously enqueued in command_queue \n     * to complete before it completes. This command blocks command execution, that is, any \n     * following commands enqueued after it do not execute until it completes. This command \n     * returns an event which can be waited on, i.e. this event can be waited on to insure that \n     * all events either in the event_wait_list or all previously enqueued commands, queued \n     * before this command to command_queue, have completed.\n     */\n    cl_int enqueueBarrierWithWaitList(\n        const vector<Event> *events = 0,\n        Event *event = 0) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueBarrierWithWaitList(\n                object_,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_BARRIER_WAIT_LIST_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n    \n    /**\n     * Enqueues a command to indicate with which device a set of memory objects\n     * should be associated.\n     */\n    cl_int enqueueMigrateMemObjects(\n        const vector<Memory> &memObjects,\n        cl_mem_migration_flags flags,\n        const vector<Event>* events = NULL,\n        Event* event = NULL\n        ) const\n    {\n        cl_event tmp;\n        \n        vector<cl_mem> localMemObjects(memObjects.size());\n\n        for( int i = 0; i < (int)memObjects.size(); ++i ) {\n            localMemObjects[i] = memObjects[i]();\n        }\n        \n        cl_int err = detail::errHandler(\n            ::clEnqueueMigrateMemObjects(\n                object_, \n                (cl_uint)memObjects.size(), \n                localMemObjects.data(),\n                flags,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_UNMAP_MEM_OBJECT_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210\n    /**\n     * Enqueues a command that will allow the host associate ranges within a set of\n     * SVM allocations with a device.\n     * @param sizes - The length from each pointer to migrate.\n     */\n    template<typename T>\n    cl_int enqueueMigrateSVM(\n        const cl::vector<T*> &svmRawPointers,\n        const cl::vector<size_type> &sizes,\n        cl_mem_migration_flags flags = 0,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(::clEnqueueSVMMigrateMem(\n            object_,\n            svmRawPointers.size(), static_cast<void**>(svmRawPointers.data()),\n            sizes.data(), // array of sizes not passed\n            flags,\n            (events != NULL) ? (cl_uint)events->size() : 0,\n            (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL,\n            (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_MIGRATE_SVM_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    /**\n     * Enqueues a command that will allow the host associate a set of SVM allocations with\n     * a device.\n     */\n    template<typename T>\n    cl_int enqueueMigrateSVM(\n        const cl::vector<T*> &svmRawPointers,\n        cl_mem_migration_flags flags = 0,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        return enqueueMigrateSVM(svmRawPointers, cl::vector<size_type>(svmRawPointers.size()), flags, events, event);\n    }\n\n\n    /**\n     * Enqueues a command that will allow the host associate ranges within a set of\n     * SVM allocations with a device.\n     * @param sizes - The length from each pointer to migrate.\n     */\n    template<typename T, class D>\n    cl_int enqueueMigrateSVM(\n        const cl::vector<cl::pointer<T, D>> &svmPointers,\n        const cl::vector<size_type> &sizes,\n        cl_mem_migration_flags flags = 0,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl::vector<void*> svmRawPointers;\n        svmRawPointers.reserve(svmPointers.size());\n        for (auto p : svmPointers) {\n            svmRawPointers.push_back(static_cast<void*>(p.get()));\n        }\n\n        return enqueueMigrateSVM(svmRawPointers, sizes, flags, events, event);\n    }\n\n\n    /**\n     * Enqueues a command that will allow the host associate a set of SVM allocations with\n     * a device.\n     */\n    template<typename T, class D>\n    cl_int enqueueMigrateSVM(\n        const cl::vector<cl::pointer<T, D>> &svmPointers,\n        cl_mem_migration_flags flags = 0,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        return enqueueMigrateSVM(svmPointers, cl::vector<size_type>(svmPointers.size()), flags, events, event);\n    }\n\n    /**\n     * Enqueues a command that will allow the host associate ranges within a set of\n     * SVM allocations with a device.\n     * @param sizes - The length from the beginning of each container to migrate.\n     */\n    template<typename T, class Alloc>\n    cl_int enqueueMigrateSVM(\n        const cl::vector<cl::vector<T, Alloc>> &svmContainers,\n        const cl::vector<size_type> &sizes,\n        cl_mem_migration_flags flags = 0,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl::vector<void*> svmRawPointers;\n        svmRawPointers.reserve(svmContainers.size());\n        for (auto p : svmContainers) {\n            svmRawPointers.push_back(static_cast<void*>(p.data()));\n        }\n\n        return enqueueMigrateSVM(svmRawPointers, sizes, flags, events, event);\n    }\n\n    /**\n     * Enqueues a command that will allow the host associate a set of SVM allocations with\n     * a device.\n     */\n    template<typename T, class Alloc>\n    cl_int enqueueMigrateSVM(\n        const cl::vector<cl::vector<T, Alloc>> &svmContainers,\n        cl_mem_migration_flags flags = 0,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        return enqueueMigrateSVM(svmContainers, cl::vector<size_type>(svmContainers.size()), flags, events, event);\n    }\n\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 210\n    \n    cl_int enqueueNDRangeKernel(\n        const Kernel& kernel,\n        const NDRange& offset,\n        const NDRange& global,\n        const NDRange& local = NullRange,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueNDRangeKernel(\n                object_, kernel(), (cl_uint) global.dimensions(),\n                offset.dimensions() != 0 ? (const size_type*) offset : NULL,\n                (const size_type*) global,\n                local.dimensions() != 0 ? (const size_type*) local : NULL,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_NDRANGE_KERNEL_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n#if defined(CL_USE_DEPRECATED_OPENCL_1_2_APIS)\n    CL_API_PREFIX__VERSION_1_2_DEPRECATED cl_int enqueueTask(\n        const Kernel& kernel,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const CL_API_SUFFIX__VERSION_1_2_DEPRECATED\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueTask(\n                object_, kernel(),\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_TASK_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n#endif // #if defined(CL_USE_DEPRECATED_OPENCL_1_2_APIS)\n\n    cl_int enqueueNativeKernel(\n        void (CL_CALLBACK *userFptr)(void *),\n        std::pair<void*, size_type> args,\n        const vector<Memory>* mem_objects = NULL,\n        const vector<const void*>* mem_locs = NULL,\n        const vector<Event>* events = NULL,\n        Event* event = NULL) const\n    {\n        size_type elements = 0;\n        if (mem_objects != NULL) {\n            elements = mem_objects->size();\n        }\n        vector<cl_mem> mems(elements);\n        for (unsigned int i = 0; i < elements; i++) {\n            mems[i] = ((*mem_objects)[i])();\n        }\n        \n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueNativeKernel(\n                object_, userFptr, args.first, args.second,\n                (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0,\n                mems.data(),\n                (mem_locs != NULL && mem_locs->size() > 0) ? (const void **) &mem_locs->front() : NULL,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_NATIVE_KERNEL);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n/**\n * Deprecated APIs for 1.2\n */\n#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS)\n    CL_API_PREFIX__VERSION_1_1_DEPRECATED \n    cl_int enqueueMarker(Event* event = NULL) const CL_API_SUFFIX__VERSION_1_1_DEPRECATED\n    {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            ::clEnqueueMarker(\n                object_, \n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_MARKER_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n\n    CL_API_PREFIX__VERSION_1_1_DEPRECATED\n    cl_int enqueueWaitForEvents(const vector<Event>& events) const CL_API_SUFFIX__VERSION_1_1_DEPRECATED\n    {\n        return detail::errHandler(\n            ::clEnqueueWaitForEvents(\n                object_,\n                (cl_uint) events.size(),\n                events.size() > 0 ? (const cl_event*) &events.front() : NULL),\n            __ENQUEUE_WAIT_FOR_EVENTS_ERR);\n    }\n#endif // defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS)\n\n    cl_int enqueueAcquireGLObjects(\n         const vector<Memory>* mem_objects = NULL,\n         const vector<Event>* events = NULL,\n         Event* event = NULL) const\n     {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n             ::clEnqueueAcquireGLObjects(\n                 object_,\n                 (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0,\n                 (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL,\n                 (events != NULL) ? (cl_uint) events->size() : 0,\n                 (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                 (event != NULL) ? &tmp : NULL),\n             __ENQUEUE_ACQUIRE_GL_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n     }\n\n    cl_int enqueueReleaseGLObjects(\n         const vector<Memory>* mem_objects = NULL,\n         const vector<Event>* events = NULL,\n         Event* event = NULL) const\n     {\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n             ::clEnqueueReleaseGLObjects(\n                 object_,\n                 (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0,\n                 (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL,\n                 (events != NULL) ? (cl_uint) events->size() : 0,\n                 (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                 (event != NULL) ? &tmp : NULL),\n             __ENQUEUE_RELEASE_GL_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n     }\n\n#if defined (CL_HPP_USE_DX_INTEROP)\ntypedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueAcquireD3D10ObjectsKHR)(\n    cl_command_queue command_queue, cl_uint num_objects,\n    const cl_mem* mem_objects, cl_uint num_events_in_wait_list,\n    const cl_event* event_wait_list, cl_event* event);\ntypedef CL_API_ENTRY cl_int (CL_API_CALL *PFN_clEnqueueReleaseD3D10ObjectsKHR)(\n    cl_command_queue command_queue, cl_uint num_objects,\n    const cl_mem* mem_objects,  cl_uint num_events_in_wait_list,\n    const cl_event* event_wait_list, cl_event* event);\n\n    cl_int enqueueAcquireD3D10Objects(\n         const vector<Memory>* mem_objects = NULL,\n         const vector<Event>* events = NULL,\n         Event* event = NULL) const\n    {\n        static PFN_clEnqueueAcquireD3D10ObjectsKHR pfn_clEnqueueAcquireD3D10ObjectsKHR = NULL;\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n        cl_context context = getInfo<CL_QUEUE_CONTEXT>();\n        cl::Device device(getInfo<CL_QUEUE_DEVICE>());\n        cl_platform_id platform = device.getInfo<CL_DEVICE_PLATFORM>();\n        CL_HPP_INIT_CL_EXT_FCN_PTR_PLATFORM_(platform, clEnqueueAcquireD3D10ObjectsKHR);\n#endif\n#if CL_HPP_TARGET_OPENCL_VERSION >= 110\n        CL_HPP_INIT_CL_EXT_FCN_PTR_(clEnqueueAcquireD3D10ObjectsKHR);\n#endif\n        \n        cl_event tmp;\n        cl_int err = detail::errHandler(\n             pfn_clEnqueueAcquireD3D10ObjectsKHR(\n                 object_,\n                 (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0,\n                 (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL,\n                 (events != NULL) ? (cl_uint) events->size() : 0,\n                 (events != NULL) ? (cl_event*) &events->front() : NULL,\n                 (event != NULL) ? &tmp : NULL),\n             __ENQUEUE_ACQUIRE_GL_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n     }\n\n    cl_int enqueueReleaseD3D10Objects(\n         const vector<Memory>* mem_objects = NULL,\n         const vector<Event>* events = NULL,\n         Event* event = NULL) const\n    {\n        static PFN_clEnqueueReleaseD3D10ObjectsKHR pfn_clEnqueueReleaseD3D10ObjectsKHR = NULL;\n#if CL_HPP_TARGET_OPENCL_VERSION >= 120\n        cl_context context = getInfo<CL_QUEUE_CONTEXT>();\n        cl::Device device(getInfo<CL_QUEUE_DEVICE>());\n        cl_platform_id platform = device.getInfo<CL_DEVICE_PLATFORM>();\n        CL_HPP_INIT_CL_EXT_FCN_PTR_PLATFORM_(platform, clEnqueueReleaseD3D10ObjectsKHR);\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 120\n#if CL_HPP_TARGET_OPENCL_VERSION >= 110\n        CL_HPP_INIT_CL_EXT_FCN_PTR_(clEnqueueReleaseD3D10ObjectsKHR);\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 110\n\n        cl_event tmp;\n        cl_int err = detail::errHandler(\n            pfn_clEnqueueReleaseD3D10ObjectsKHR(\n                object_,\n                (mem_objects != NULL) ? (cl_uint) mem_objects->size() : 0,\n                (mem_objects != NULL && mem_objects->size() > 0) ? (const cl_mem *) &mem_objects->front(): NULL,\n                (events != NULL) ? (cl_uint) events->size() : 0,\n                (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n                (event != NULL) ? &tmp : NULL),\n            __ENQUEUE_RELEASE_GL_ERR);\n\n        if (event != NULL && err == CL_SUCCESS)\n            *event = tmp;\n\n        return err;\n    }\n#endif\n\n/**\n * Deprecated APIs for 1.2\n */\n#if defined(CL_USE_DEPRECATED_OPENCL_1_1_APIS)\n    CL_API_PREFIX__VERSION_1_1_DEPRECATED\n    cl_int enqueueBarrier() const CL_API_SUFFIX__VERSION_1_1_DEPRECATED\n    {\n        return detail::errHandler(\n            ::clEnqueueBarrier(object_),\n            __ENQUEUE_BARRIER_ERR);\n    }\n#endif // CL_USE_DEPRECATED_OPENCL_1_1_APIS\n\n    cl_int flush() const\n    {\n        return detail::errHandler(::clFlush(object_), __FLUSH_ERR);\n    }\n\n    cl_int finish() const\n    {\n        return detail::errHandler(::clFinish(object_), __FINISH_ERR);\n    }\n}; // CommandQueue\n\nCL_HPP_DEFINE_STATIC_MEMBER_ std::once_flag CommandQueue::default_initialized_;\nCL_HPP_DEFINE_STATIC_MEMBER_ CommandQueue CommandQueue::default_;\nCL_HPP_DEFINE_STATIC_MEMBER_ cl_int CommandQueue::default_error_ = CL_SUCCESS;\n\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\nenum class DeviceQueueProperties : cl_command_queue_properties\n{\n    None = 0,\n    Profiling = CL_QUEUE_PROFILING_ENABLE,\n};\n\ninline DeviceQueueProperties operator|(DeviceQueueProperties lhs, DeviceQueueProperties rhs)\n{\n    return static_cast<DeviceQueueProperties>(static_cast<cl_command_queue_properties>(lhs) | static_cast<cl_command_queue_properties>(rhs));\n}\n\n/*! \\class DeviceCommandQueue\n * \\brief DeviceCommandQueue interface for device cl_command_queues.\n */\nclass DeviceCommandQueue : public detail::Wrapper<cl_command_queue>\n{\npublic:\n\n    /*!\n     * Trivial empty constructor to create a null queue.\n     */\n    DeviceCommandQueue() { }\n\n    /*!\n     * Default construct device command queue on default context and device\n     */\n    DeviceCommandQueue(DeviceQueueProperties properties, cl_int* err = NULL)\n    {\n        cl_int error;\n        cl::Context context = cl::Context::getDefault();\n        cl::Device device = cl::Device::getDefault();\n\n        cl_command_queue_properties mergedProperties =\n            CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE | CL_QUEUE_ON_DEVICE | static_cast<cl_command_queue_properties>(properties);\n\n        cl_queue_properties queue_properties[] = {\n            CL_QUEUE_PROPERTIES, mergedProperties, 0 };\n        object_ = ::clCreateCommandQueueWithProperties(\n            context(), device(), queue_properties, &error);\n\n        detail::errHandler(error, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    /*!\n     * Create a device command queue for a specified device in the passed context.\n     */\n    DeviceCommandQueue(\n        const Context& context,\n        const Device& device,\n        DeviceQueueProperties properties = DeviceQueueProperties::None,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        cl_command_queue_properties mergedProperties =\n            CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE | CL_QUEUE_ON_DEVICE | static_cast<cl_command_queue_properties>(properties);\n        cl_queue_properties queue_properties[] = {\n            CL_QUEUE_PROPERTIES, mergedProperties, 0 };\n        object_ = ::clCreateCommandQueueWithProperties(\n            context(), device(), queue_properties, &error);\n\n        detail::errHandler(error, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    /*!\n     * Create a device command queue for a specified device in the passed context.\n     */\n    DeviceCommandQueue(\n        const Context& context,\n        const Device& device,\n        cl_uint queueSize,\n        DeviceQueueProperties properties = DeviceQueueProperties::None,\n        cl_int* err = NULL)\n    {\n        cl_int error;\n\n        cl_command_queue_properties mergedProperties =\n            CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE | CL_QUEUE_ON_DEVICE | static_cast<cl_command_queue_properties>(properties);\n        cl_queue_properties queue_properties[] = {\n            CL_QUEUE_PROPERTIES, mergedProperties,\n            CL_QUEUE_SIZE, queueSize, \n            0 };\n        object_ = ::clCreateCommandQueueWithProperties(\n            context(), device(), queue_properties, &error);\n\n        detail::errHandler(error, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n\n    /*! \\brief Constructor from cl_command_queue - takes ownership.\n    *\n    * \\param retainObject will cause the constructor to retain its cl object.\n    *                     Defaults to false to maintain compatibility with\n    *                     earlier versions.\n    */\n    explicit DeviceCommandQueue(const cl_command_queue& commandQueue, bool retainObject = false) :\n        detail::Wrapper<cl_type>(commandQueue, retainObject) { }\n\n    DeviceCommandQueue& operator = (const cl_command_queue& rhs)\n    {\n        detail::Wrapper<cl_type>::operator=(rhs);\n        return *this;\n    }\n\n    /*! \\brief Copy constructor to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    DeviceCommandQueue(const DeviceCommandQueue& queue) : detail::Wrapper<cl_type>(queue) {}\n\n    /*! \\brief Copy assignment to forward copy to the superclass correctly.\n     * Required for MSVC.\n     */\n    DeviceCommandQueue& operator = (const DeviceCommandQueue &queue)\n    {\n        detail::Wrapper<cl_type>::operator=(queue);\n        return *this;\n    }\n\n    /*! \\brief Move constructor to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    DeviceCommandQueue(DeviceCommandQueue&& queue) CL_HPP_NOEXCEPT_ : detail::Wrapper<cl_type>(std::move(queue)) {}\n\n    /*! \\brief Move assignment to forward move to the superclass correctly.\n     * Required for MSVC.\n     */\n    DeviceCommandQueue& operator = (DeviceCommandQueue &&queue)\n    {\n        detail::Wrapper<cl_type>::operator=(std::move(queue));\n        return *this;\n    }\n\n    template <typename T>\n    cl_int getInfo(cl_command_queue_info name, T* param) const\n    {\n        return detail::errHandler(\n            detail::getInfo(\n            &::clGetCommandQueueInfo, object_, name, param),\n            __GET_COMMAND_QUEUE_INFO_ERR);\n    }\n\n    template <cl_command_queue_info name> typename\n        detail::param_traits<detail::cl_command_queue_info, name>::param_type\n        getInfo(cl_int* err = NULL) const\n    {\n        typename detail::param_traits<\n            detail::cl_command_queue_info, name>::param_type param;\n        cl_int result = getInfo(name, &param);\n        if (err != NULL) {\n            *err = result;\n        }\n        return param;\n    }\n\n    /*!\n     * Create a new default device command queue for the default device,\n     * in the default context and of the default size.\n     * If there is already a default queue for the specified device this\n     * function will return the pre-existing queue.\n     */\n    static DeviceCommandQueue makeDefault(\n        cl_int *err = nullptr)\n    {\n        cl_int error;\n        cl::Context context = cl::Context::getDefault();\n        cl::Device device = cl::Device::getDefault();\n\n        cl_command_queue_properties properties =\n            CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE | CL_QUEUE_ON_DEVICE | CL_QUEUE_ON_DEVICE_DEFAULT;\n        cl_queue_properties queue_properties[] = {\n            CL_QUEUE_PROPERTIES, properties,\n            0 };\n        DeviceCommandQueue deviceQueue(\n            ::clCreateCommandQueueWithProperties(\n            context(), device(), queue_properties, &error));\n\n        detail::errHandler(error, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n\n        return deviceQueue;\n    }\n\n    /*!\n     * Create a new default device command queue for the specified device\n     * and of the default size.\n     * If there is already a default queue for the specified device this\n     * function will return the pre-existing queue.\n     */\n    static DeviceCommandQueue makeDefault(\n        const Context &context, const Device &device, cl_int *err = nullptr)\n    {\n        cl_int error;\n\n        cl_command_queue_properties properties =\n            CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE | CL_QUEUE_ON_DEVICE | CL_QUEUE_ON_DEVICE_DEFAULT;\n        cl_queue_properties queue_properties[] = {\n            CL_QUEUE_PROPERTIES, properties,\n            0 };\n        DeviceCommandQueue deviceQueue(\n            ::clCreateCommandQueueWithProperties(\n            context(), device(), queue_properties, &error));\n\n        detail::errHandler(error, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n\n        return deviceQueue;\n    }\n\n    /*!\n     * Create a new default device command queue for the specified device \n     * and of the requested size in bytes.\n     * If there is already a default queue for the specified device this\n     * function will return the pre-existing queue.\n     */\n    static DeviceCommandQueue makeDefault(\n        const Context &context, const Device &device, cl_uint queueSize, cl_int *err = nullptr)\n    {\n        cl_int error;\n\n        cl_command_queue_properties properties =\n            CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE | CL_QUEUE_ON_DEVICE | CL_QUEUE_ON_DEVICE_DEFAULT;\n        cl_queue_properties queue_properties[] = {\n            CL_QUEUE_PROPERTIES, properties,\n            CL_QUEUE_SIZE, queueSize,\n            0 };\n        DeviceCommandQueue deviceQueue(\n            ::clCreateCommandQueueWithProperties(\n                context(), device(), queue_properties, &error));\n\n        detail::errHandler(error, __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n\n        return deviceQueue;\n    }\n\n\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 210\n    /*!\n     * Modify the default device command queue to be used for subsequent kernels.\n     * This can update the default command queue for a device repeatedly to account\n     * for kernels that rely on the default.\n     * @return updated default device command queue.\n     */\n    static DeviceCommandQueue updateDefault(const Context &context, const Device &device, const DeviceCommandQueue &default_queue, cl_int *err = nullptr)\n    {\n        cl_int error;\n        error = clSetDefaultDeviceCommandQueue(context.get(), device.get(), default_queue.get());\n\n        detail::errHandler(error, __SET_DEFAULT_DEVICE_COMMAND_QUEUE_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n        return default_queue;\n    }\n\n    /*!\n     * Return the current default command queue for the specified command queue\n     */\n    static DeviceCommandQueue getDefault(const CommandQueue &queue, cl_int * err = NULL)\n    {\n        return queue.getInfo<CL_QUEUE_DEVICE_DEFAULT>(err);\n    }\n\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 210\n}; // DeviceCommandQueue\n\nnamespace detail\n{\n    // Specialization for device command queue\n    template <>\n    struct KernelArgumentHandler<cl::DeviceCommandQueue, void>\n    {\n        static size_type size(const cl::DeviceCommandQueue&) { return sizeof(cl_command_queue); }\n        static const cl_command_queue* ptr(const cl::DeviceCommandQueue& value) { return &(value()); }\n    };\n} // namespace detail\n\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\n\ntemplate< typename IteratorType >\nBuffer::Buffer(\n    const Context &context,\n    IteratorType startIterator,\n    IteratorType endIterator,\n    bool readOnly,\n    bool useHostPtr,\n    cl_int* err)\n{\n    typedef typename std::iterator_traits<IteratorType>::value_type DataType;\n    cl_int error;\n\n    cl_mem_flags flags = 0;\n    if( readOnly ) {\n        flags |= CL_MEM_READ_ONLY;\n    }\n    else {\n        flags |= CL_MEM_READ_WRITE;\n    }\n    if( useHostPtr ) {\n        flags |= CL_MEM_USE_HOST_PTR;\n    }\n    \n    size_type size = sizeof(DataType)*(endIterator - startIterator);\n\n    if( useHostPtr ) {\n        object_ = ::clCreateBuffer(context(), flags, size, static_cast<DataType*>(&*startIterator), &error);\n    } else {\n        object_ = ::clCreateBuffer(context(), flags, size, 0, &error);\n    }\n\n    detail::errHandler(error, __CREATE_BUFFER_ERR);\n    if (err != NULL) {\n        *err = error;\n    }\n\n    if( !useHostPtr ) {\n        CommandQueue queue(context, 0, &error);\n        detail::errHandler(error, __CREATE_BUFFER_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n\n        error = cl::copy(queue, startIterator, endIterator, *this);\n        detail::errHandler(error, __CREATE_BUFFER_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n}\n\ntemplate< typename IteratorType >\nBuffer::Buffer(\n    const CommandQueue &queue,\n    IteratorType startIterator,\n    IteratorType endIterator,\n    bool readOnly,\n    bool useHostPtr,\n    cl_int* err)\n{\n    typedef typename std::iterator_traits<IteratorType>::value_type DataType;\n    cl_int error;\n\n    cl_mem_flags flags = 0;\n    if (readOnly) {\n        flags |= CL_MEM_READ_ONLY;\n    }\n    else {\n        flags |= CL_MEM_READ_WRITE;\n    }\n    if (useHostPtr) {\n        flags |= CL_MEM_USE_HOST_PTR;\n    }\n\n    size_type size = sizeof(DataType)*(endIterator - startIterator);\n\n    Context context = queue.getInfo<CL_QUEUE_CONTEXT>();\n\n    if (useHostPtr) {\n        object_ = ::clCreateBuffer(context(), flags, size, static_cast<DataType*>(&*startIterator), &error);\n    }\n    else {\n        object_ = ::clCreateBuffer(context(), flags, size, 0, &error);\n    }\n\n    detail::errHandler(error, __CREATE_BUFFER_ERR);\n    if (err != NULL) {\n        *err = error;\n    }\n\n    if (!useHostPtr) {\n        error = cl::copy(queue, startIterator, endIterator, *this);\n        detail::errHandler(error, __CREATE_BUFFER_ERR);\n        if (err != NULL) {\n            *err = error;\n        }\n    }\n}\n\ninline cl_int enqueueReadBuffer(\n    const Buffer& buffer,\n    cl_bool blocking,\n    size_type offset,\n    size_type size,\n    void* ptr,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    return queue.enqueueReadBuffer(buffer, blocking, offset, size, ptr, events, event);\n}\n\ninline cl_int enqueueWriteBuffer(\n        const Buffer& buffer,\n        cl_bool blocking,\n        size_type offset,\n        size_type size,\n        const void* ptr,\n        const vector<Event>* events = NULL,\n        Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    return queue.enqueueWriteBuffer(buffer, blocking, offset, size, ptr, events, event);\n}\n\ninline void* enqueueMapBuffer(\n        const Buffer& buffer,\n        cl_bool blocking,\n        cl_map_flags flags,\n        size_type offset,\n        size_type size,\n        const vector<Event>* events = NULL,\n        Event* event = NULL,\n        cl_int* err = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n    detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR);\n    if (err != NULL) {\n        *err = error;\n    }\n\n    void * result = ::clEnqueueMapBuffer(\n            queue(), buffer(), blocking, flags, offset, size,\n            (events != NULL) ? (cl_uint) events->size() : 0,\n            (events != NULL && events->size() > 0) ? (cl_event*) &events->front() : NULL,\n            (cl_event*) event,\n            &error);\n\n    detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR);\n    if (err != NULL) {\n        *err = error;\n    }\n    return result;\n}\n\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n/**\n * Enqueues to the default queue a command that will allow the host to\n * update a region of a coarse-grained SVM buffer.\n * This variant takes a raw SVM pointer.\n */\ntemplate<typename T>\ninline cl_int enqueueMapSVM(\n    T* ptr,\n    cl_bool blocking,\n    cl_map_flags flags,\n    size_type size,\n    const vector<Event>* events,\n    Event* event)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n    if (error != CL_SUCCESS) {\n        return detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR);\n    }\n\n    return queue.enqueueMapSVM(\n        ptr, blocking, flags, size, events, event);\n}\n\n/**\n * Enqueues to the default queue a command that will allow the host to \n * update a region of a coarse-grained SVM buffer.\n * This variant takes a cl::pointer instance.\n */\ntemplate<typename T, class D>\ninline cl_int enqueueMapSVM(\n    cl::pointer<T, D> ptr,\n    cl_bool blocking,\n    cl_map_flags flags,\n    size_type size,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n    if (error != CL_SUCCESS) {\n        return detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR);\n    }\n\n    return queue.enqueueMapSVM(\n        ptr, blocking, flags, size, events, event);\n}\n\n/**\n * Enqueues to the default queue a command that will allow the host to\n * update a region of a coarse-grained SVM buffer.\n * This variant takes a cl::vector instance.\n */\ntemplate<typename T, class Alloc>\ninline cl_int enqueueMapSVM(\n    cl::vector<T, Alloc> container,\n    cl_bool blocking,\n    cl_map_flags flags,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n    if (error != CL_SUCCESS) {\n        return detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR);\n    }\n\n    return queue.enqueueMapSVM(\n        container, blocking, flags, events, event);\n}\n\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\ninline cl_int enqueueUnmapMemObject(\n    const Memory& memory,\n    void* mapped_ptr,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n    detail::errHandler(error, __ENQUEUE_MAP_BUFFER_ERR);\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    cl_event tmp;\n    cl_int err = detail::errHandler(\n        ::clEnqueueUnmapMemObject(\n        queue(), memory(), mapped_ptr,\n        (events != NULL) ? (cl_uint)events->size() : 0,\n        (events != NULL && events->size() > 0) ? (cl_event*)&events->front() : NULL,\n        (event != NULL) ? &tmp : NULL),\n        __ENQUEUE_UNMAP_MEM_OBJECT_ERR);\n\n    if (event != NULL && err == CL_SUCCESS)\n        *event = tmp;\n\n    return err;\n}\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n/**\n * Enqueues to the default queue a command that will release a coarse-grained \n * SVM buffer back to the OpenCL runtime.\n * This variant takes a raw SVM pointer.\n */\ntemplate<typename T>\ninline cl_int enqueueUnmapSVM(\n    T* ptr,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n    if (error != CL_SUCCESS) {\n        return detail::errHandler(error, __ENQUEUE_UNMAP_MEM_OBJECT_ERR);\n    }\n\n    return detail::errHandler(queue.enqueueUnmapSVM(ptr, events, event), \n        __ENQUEUE_UNMAP_MEM_OBJECT_ERR);\n\n}\n\n/**\n * Enqueues to the default queue a command that will release a coarse-grained \n * SVM buffer back to the OpenCL runtime.\n * This variant takes a cl::pointer instance.\n */\ntemplate<typename T, class D>\ninline cl_int enqueueUnmapSVM(\n    cl::pointer<T, D> &ptr,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n    if (error != CL_SUCCESS) {\n        return detail::errHandler(error, __ENQUEUE_UNMAP_MEM_OBJECT_ERR);\n    }\n\n    return detail::errHandler(queue.enqueueUnmapSVM(ptr, events, event),\n        __ENQUEUE_UNMAP_MEM_OBJECT_ERR);\n}\n\n/**\n * Enqueues to the default queue a command that will release a coarse-grained \n * SVM buffer back to the OpenCL runtime.\n * This variant takes a cl::vector instance.\n */\ntemplate<typename T, class Alloc>\ninline cl_int enqueueUnmapSVM(\n    cl::vector<T, Alloc> &container,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n    if (error != CL_SUCCESS) {\n        return detail::errHandler(error, __ENQUEUE_UNMAP_MEM_OBJECT_ERR);\n    }\n\n    return detail::errHandler(queue.enqueueUnmapSVM(container, events, event),\n        __ENQUEUE_UNMAP_MEM_OBJECT_ERR);\n}\n\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\ninline cl_int enqueueCopyBuffer(\n        const Buffer& src,\n        const Buffer& dst,\n        size_type src_offset,\n        size_type dst_offset,\n        size_type size,\n        const vector<Event>* events = NULL,\n        Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    return queue.enqueueCopyBuffer(src, dst, src_offset, dst_offset, size, events, event);\n}\n\n/**\n * Blocking copy operation between iterators and a buffer.\n * Host to Device.\n * Uses default command queue.\n */\ntemplate< typename IteratorType >\ninline cl_int copy( IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer )\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n    if (error != CL_SUCCESS)\n        return error;\n\n    return cl::copy(queue, startIterator, endIterator, buffer);\n}\n\n/**\n * Blocking copy operation between iterators and a buffer.\n * Device to Host.\n * Uses default command queue.\n */\ntemplate< typename IteratorType >\ninline cl_int copy( const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator )\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n    if (error != CL_SUCCESS)\n        return error;\n\n    return cl::copy(queue, buffer, startIterator, endIterator);\n}\n\n/**\n * Blocking copy operation between iterators and a buffer.\n * Host to Device.\n * Uses specified queue.\n */\ntemplate< typename IteratorType >\ninline cl_int copy( const CommandQueue &queue, IteratorType startIterator, IteratorType endIterator, cl::Buffer &buffer )\n{\n    typedef typename std::iterator_traits<IteratorType>::value_type DataType;\n    cl_int error;\n    \n    size_type length = endIterator-startIterator;\n    size_type byteLength = length*sizeof(DataType);\n\n    DataType *pointer = \n        static_cast<DataType*>(queue.enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_WRITE, 0, byteLength, 0, 0, &error));\n    // if exceptions enabled, enqueueMapBuffer will throw\n    if( error != CL_SUCCESS ) {\n        return error;\n    }\n#if defined(_MSC_VER)\n    std::copy(\n        startIterator, \n        endIterator, \n        stdext::checked_array_iterator<DataType*>(\n            pointer, length));\n#else\n    std::copy(startIterator, endIterator, pointer);\n#endif\n    Event endEvent;\n    error = queue.enqueueUnmapMemObject(buffer, pointer, 0, &endEvent);\n    // if exceptions enabled, enqueueUnmapMemObject will throw\n    if( error != CL_SUCCESS ) { \n        return error;\n    }\n    endEvent.wait();\n    return CL_SUCCESS;\n}\n\n/**\n * Blocking copy operation between iterators and a buffer.\n * Device to Host.\n * Uses specified queue.\n */\ntemplate< typename IteratorType >\ninline cl_int copy( const CommandQueue &queue, const cl::Buffer &buffer, IteratorType startIterator, IteratorType endIterator )\n{\n    typedef typename std::iterator_traits<IteratorType>::value_type DataType;\n    cl_int error;\n        \n    size_type length = endIterator-startIterator;\n    size_type byteLength = length*sizeof(DataType);\n\n    DataType *pointer = \n        static_cast<DataType*>(queue.enqueueMapBuffer(buffer, CL_TRUE, CL_MAP_READ, 0, byteLength, 0, 0, &error));\n    // if exceptions enabled, enqueueMapBuffer will throw\n    if( error != CL_SUCCESS ) {\n        return error;\n    }\n    std::copy(pointer, pointer + length, startIterator);\n    Event endEvent;\n    error = queue.enqueueUnmapMemObject(buffer, pointer, 0, &endEvent);\n    // if exceptions enabled, enqueueUnmapMemObject will throw\n    if( error != CL_SUCCESS ) { \n        return error;\n    }\n    endEvent.wait();\n    return CL_SUCCESS;\n}\n\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n/**\n * Blocking SVM map operation - performs a blocking map underneath.\n */\ntemplate<typename T, class Alloc>\ninline cl_int mapSVM(cl::vector<T, Alloc> &container)\n{\n    return enqueueMapSVM(container, CL_TRUE, CL_MAP_READ | CL_MAP_WRITE);\n}\n\n/**\n* Blocking SVM map operation - performs a blocking map underneath.\n*/\ntemplate<typename T, class Alloc>\ninline cl_int unmapSVM(cl::vector<T, Alloc> &container)\n{\n    return enqueueUnmapSVM(container);\n}\n\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 110\ninline cl_int enqueueReadBufferRect(\n    const Buffer& buffer,\n    cl_bool blocking,\n    const array<size_type, 3>& buffer_offset,\n    const array<size_type, 3>& host_offset,\n    const array<size_type, 3>& region,\n    size_type buffer_row_pitch,\n    size_type buffer_slice_pitch,\n    size_type host_row_pitch,\n    size_type host_slice_pitch,\n    void *ptr,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    return queue.enqueueReadBufferRect(\n        buffer, \n        blocking, \n        buffer_offset, \n        host_offset,\n        region,\n        buffer_row_pitch,\n        buffer_slice_pitch,\n        host_row_pitch,\n        host_slice_pitch,\n        ptr, \n        events, \n        event);\n}\n\ninline cl_int enqueueWriteBufferRect(\n    const Buffer& buffer,\n    cl_bool blocking,\n    const array<size_type, 3>& buffer_offset,\n    const array<size_type, 3>& host_offset,\n    const array<size_type, 3>& region,\n    size_type buffer_row_pitch,\n    size_type buffer_slice_pitch,\n    size_type host_row_pitch,\n    size_type host_slice_pitch,\n    const void *ptr,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    return queue.enqueueWriteBufferRect(\n        buffer, \n        blocking, \n        buffer_offset, \n        host_offset,\n        region,\n        buffer_row_pitch,\n        buffer_slice_pitch,\n        host_row_pitch,\n        host_slice_pitch,\n        ptr, \n        events, \n        event);\n}\n\ninline cl_int enqueueCopyBufferRect(\n    const Buffer& src,\n    const Buffer& dst,\n    const array<size_type, 3>& src_origin,\n    const array<size_type, 3>& dst_origin,\n    const array<size_type, 3>& region,\n    size_type src_row_pitch,\n    size_type src_slice_pitch,\n    size_type dst_row_pitch,\n    size_type dst_slice_pitch,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    return queue.enqueueCopyBufferRect(\n        src,\n        dst,\n        src_origin,\n        dst_origin,\n        region,\n        src_row_pitch,\n        src_slice_pitch,\n        dst_row_pitch,\n        dst_slice_pitch,\n        events, \n        event);\n}\n#endif // CL_HPP_TARGET_OPENCL_VERSION >= 110\n\ninline cl_int enqueueReadImage(\n    const Image& image,\n    cl_bool blocking,\n    const array<size_type, 3>& origin,\n    const array<size_type, 3>& region,\n    size_type row_pitch,\n    size_type slice_pitch,\n    void* ptr,\n    const vector<Event>* events = NULL,\n    Event* event = NULL) \n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    return queue.enqueueReadImage(\n        image,\n        blocking,\n        origin,\n        region,\n        row_pitch,\n        slice_pitch,\n        ptr,\n        events, \n        event);\n}\n\ninline cl_int enqueueWriteImage(\n    const Image& image,\n    cl_bool blocking,\n    const array<size_type, 3>& origin,\n    const array<size_type, 3>& region,\n    size_type row_pitch,\n    size_type slice_pitch,\n    const void* ptr,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    return queue.enqueueWriteImage(\n        image,\n        blocking,\n        origin,\n        region,\n        row_pitch,\n        slice_pitch,\n        ptr,\n        events, \n        event);\n}\n\ninline cl_int enqueueCopyImage(\n    const Image& src,\n    const Image& dst,\n    const array<size_type, 3>& src_origin,\n    const array<size_type, 3>& dst_origin,\n    const array<size_type, 3>& region,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    return queue.enqueueCopyImage(\n        src,\n        dst,\n        src_origin,\n        dst_origin,\n        region,\n        events,\n        event);\n}\n\ninline cl_int enqueueCopyImageToBuffer(\n    const Image& src,\n    const Buffer& dst,\n    const array<size_type, 3>& src_origin,\n    const array<size_type, 3>& region,\n    size_type dst_offset,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    return queue.enqueueCopyImageToBuffer(\n        src,\n        dst,\n        src_origin,\n        region,\n        dst_offset,\n        events,\n        event);\n}\n\ninline cl_int enqueueCopyBufferToImage(\n    const Buffer& src,\n    const Image& dst,\n    size_type src_offset,\n    const array<size_type, 3>& dst_origin,\n    const array<size_type, 3>& region,\n    const vector<Event>* events = NULL,\n    Event* event = NULL)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    return queue.enqueueCopyBufferToImage(\n        src,\n        dst,\n        src_offset,\n        dst_origin,\n        region,\n        events,\n        event);\n}\n\n\ninline cl_int flush(void)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    }\n\n    return queue.flush();\n}\n\ninline cl_int finish(void)\n{\n    cl_int error;\n    CommandQueue queue = CommandQueue::getDefault(&error);\n\n    if (error != CL_SUCCESS) {\n        return error;\n    } \n\n\n    return queue.finish();\n}\n\nclass EnqueueArgs\n{\nprivate:\n    CommandQueue queue_;\n    const NDRange offset_;\n    const NDRange global_;\n    const NDRange local_;\n    vector<Event> events_;\n\n    template<typename... Ts>\n    friend class KernelFunctor;\n\npublic:\n    EnqueueArgs(NDRange global) : \n      queue_(CommandQueue::getDefault()),\n      offset_(NullRange), \n      global_(global),\n      local_(NullRange)\n    {\n\n    }\n\n    EnqueueArgs(NDRange global, NDRange local) : \n      queue_(CommandQueue::getDefault()),\n      offset_(NullRange), \n      global_(global),\n      local_(local)\n    {\n\n    }\n\n    EnqueueArgs(NDRange offset, NDRange global, NDRange local) : \n      queue_(CommandQueue::getDefault()),\n      offset_(offset), \n      global_(global),\n      local_(local)\n    {\n\n    }\n\n    EnqueueArgs(Event e, NDRange global) : \n      queue_(CommandQueue::getDefault()),\n      offset_(NullRange), \n      global_(global),\n      local_(NullRange)\n    {\n        events_.push_back(e);\n    }\n\n    EnqueueArgs(Event e, NDRange global, NDRange local) : \n      queue_(CommandQueue::getDefault()),\n      offset_(NullRange), \n      global_(global),\n      local_(local)\n    {\n        events_.push_back(e);\n    }\n\n    EnqueueArgs(Event e, NDRange offset, NDRange global, NDRange local) : \n      queue_(CommandQueue::getDefault()),\n      offset_(offset), \n      global_(global),\n      local_(local)\n    {\n        events_.push_back(e);\n    }\n\n    EnqueueArgs(const vector<Event> &events, NDRange global) : \n      queue_(CommandQueue::getDefault()),\n      offset_(NullRange), \n      global_(global),\n      local_(NullRange),\n      events_(events)\n    {\n\n    }\n\n    EnqueueArgs(const vector<Event> &events, NDRange global, NDRange local) : \n      queue_(CommandQueue::getDefault()),\n      offset_(NullRange), \n      global_(global),\n      local_(local),\n      events_(events)\n    {\n\n    }\n\n    EnqueueArgs(const vector<Event> &events, NDRange offset, NDRange global, NDRange local) : \n      queue_(CommandQueue::getDefault()),\n      offset_(offset), \n      global_(global),\n      local_(local),\n      events_(events)\n    {\n\n    }\n\n    EnqueueArgs(CommandQueue &queue, NDRange global) : \n      queue_(queue),\n      offset_(NullRange), \n      global_(global),\n      local_(NullRange)\n    {\n\n    }\n\n    EnqueueArgs(CommandQueue &queue, NDRange global, NDRange local) : \n      queue_(queue),\n      offset_(NullRange), \n      global_(global),\n      local_(local)\n    {\n\n    }\n\n    EnqueueArgs(CommandQueue &queue, NDRange offset, NDRange global, NDRange local) : \n      queue_(queue),\n      offset_(offset), \n      global_(global),\n      local_(local)\n    {\n\n    }\n\n    EnqueueArgs(CommandQueue &queue, Event e, NDRange global) : \n      queue_(queue),\n      offset_(NullRange), \n      global_(global),\n      local_(NullRange)\n    {\n        events_.push_back(e);\n    }\n\n    EnqueueArgs(CommandQueue &queue, Event e, NDRange global, NDRange local) : \n      queue_(queue),\n      offset_(NullRange), \n      global_(global),\n      local_(local)\n    {\n        events_.push_back(e);\n    }\n\n    EnqueueArgs(CommandQueue &queue, Event e, NDRange offset, NDRange global, NDRange local) : \n      queue_(queue),\n      offset_(offset), \n      global_(global),\n      local_(local)\n    {\n        events_.push_back(e);\n    }\n\n    EnqueueArgs(CommandQueue &queue, const vector<Event> &events, NDRange global) : \n      queue_(queue),\n      offset_(NullRange), \n      global_(global),\n      local_(NullRange),\n      events_(events)\n    {\n\n    }\n\n    EnqueueArgs(CommandQueue &queue, const vector<Event> &events, NDRange global, NDRange local) : \n      queue_(queue),\n      offset_(NullRange), \n      global_(global),\n      local_(local),\n      events_(events)\n    {\n\n    }\n\n    EnqueueArgs(CommandQueue &queue, const vector<Event> &events, NDRange offset, NDRange global, NDRange local) : \n      queue_(queue),\n      offset_(offset), \n      global_(global),\n      local_(local),\n      events_(events)\n    {\n\n    }\n};\n\n\n//----------------------------------------------------------------------------------------------\n\n\n/**\n * Type safe kernel functor.\n * \n */\ntemplate<typename... Ts>\nclass KernelFunctor\n{\nprivate:\n    Kernel kernel_;\n\n    template<int index, typename T0, typename... T1s>\n    void setArgs(T0&& t0, T1s&&... t1s)\n    {\n        kernel_.setArg(index, t0);\n        setArgs<index + 1, T1s...>(std::forward<T1s>(t1s)...);\n    }\n\n    template<int index, typename T0>\n    void setArgs(T0&& t0)\n    {\n        kernel_.setArg(index, t0);\n    }\n\n    template<int index>\n    void setArgs()\n    {\n    }\n\n\npublic:\n    KernelFunctor(Kernel kernel) : kernel_(kernel)\n    {}\n\n    KernelFunctor(\n        const Program& program,\n        const string name,\n        cl_int * err = NULL) :\n        kernel_(program, name.c_str(), err)\n    {}\n\n    //! \\brief Return type of the functor\n    typedef Event result_type;\n\n    /**\n     * Enqueue kernel.\n     * @param args Launch parameters of the kernel.\n     * @param t0... List of kernel arguments based on the template type of the functor.\n     */\n    Event operator() (\n        const EnqueueArgs& args,\n        Ts... ts)\n    {\n        Event event;\n        setArgs<0>(std::forward<Ts>(ts)...);\n        \n        args.queue_.enqueueNDRangeKernel(\n            kernel_,\n            args.offset_,\n            args.global_,\n            args.local_,\n            &args.events_,\n            &event);\n\n        return event;\n    }\n\n    /**\n    * Enqueue kernel with support for error code.\n    * @param args Launch parameters of the kernel.\n    * @param t0... List of kernel arguments based on the template type of the functor.\n    * @param error Out parameter returning the error code from the execution.\n    */\n    Event operator() (\n        const EnqueueArgs& args,\n        Ts... ts,\n        cl_int &error)\n    {\n        Event event;\n        setArgs<0>(std::forward<Ts>(ts)...);\n\n        error = args.queue_.enqueueNDRangeKernel(\n            kernel_,\n            args.offset_,\n            args.global_,\n            args.local_,\n            &args.events_,\n            &event);\n        \n        return event;\n    }\n\n#if CL_HPP_TARGET_OPENCL_VERSION >= 200\n    cl_int setSVMPointers(const vector<void*> &pointerList)\n    {\n        return kernel_.setSVMPointers(pointerList);\n    }\n\n    template<typename T0, typename... T1s>\n    cl_int setSVMPointers(const T0 &t0, T1s &... ts)\n    {\n        return kernel_.setSVMPointers(t0, ts...);\n    }\n#endif // #if CL_HPP_TARGET_OPENCL_VERSION >= 200\n\n    Kernel getKernel()\n    {\n        return kernel_;\n    }\n};\n\nnamespace compatibility {\n    /**\n     * Backward compatibility class to ensure that cl.hpp code works with opencl.hpp.\n     * Please use KernelFunctor directly.\n     */\n    template<typename... Ts>\n    struct make_kernel\n    {\n        typedef KernelFunctor<Ts...> FunctorType;\n\n        FunctorType functor_;\n\n        make_kernel(\n            const Program& program,\n            const string name,\n            cl_int * err = NULL) :\n            functor_(FunctorType(program, name, err))\n        {}\n\n        make_kernel(\n            const Kernel kernel) :\n            functor_(FunctorType(kernel))\n        {}\n\n        //! \\brief Return type of the functor\n        typedef Event result_type;\n\n        //! \\brief Function signature of kernel functor with no event dependency.\n        typedef Event type_(\n            const EnqueueArgs&,\n            Ts...);\n\n        Event operator()(\n            const EnqueueArgs& enqueueArgs,\n            Ts... args)\n        {\n            return functor_(\n                enqueueArgs, args...);\n        }\n    };\n} // namespace compatibility\n\n\n//----------------------------------------------------------------------------------------------------------------------\n\n#undef CL_HPP_ERR_STR_\n#if !defined(CL_HPP_USER_OVERRIDE_ERROR_STRINGS)\n#undef __GET_DEVICE_INFO_ERR               \n#undef __GET_PLATFORM_INFO_ERR             \n#undef __GET_DEVICE_IDS_ERR                \n#undef __GET_PLATFORM_IDS_ERR              \n#undef __GET_CONTEXT_INFO_ERR              \n#undef __GET_EVENT_INFO_ERR                \n#undef __GET_EVENT_PROFILE_INFO_ERR        \n#undef __GET_MEM_OBJECT_INFO_ERR           \n#undef __GET_IMAGE_INFO_ERR                \n#undef __GET_SAMPLER_INFO_ERR              \n#undef __GET_KERNEL_INFO_ERR               \n#undef __GET_KERNEL_ARG_INFO_ERR           \n#undef __GET_KERNEL_SUB_GROUP_INFO_ERR     \n#undef __GET_KERNEL_WORK_GROUP_INFO_ERR    \n#undef __GET_PROGRAM_INFO_ERR              \n#undef __GET_PROGRAM_BUILD_INFO_ERR        \n#undef __GET_COMMAND_QUEUE_INFO_ERR        \n#undef __CREATE_CONTEXT_ERR                \n#undef __CREATE_CONTEXT_FROM_TYPE_ERR      \n#undef __GET_SUPPORTED_IMAGE_FORMATS_ERR   \n#undef __CREATE_BUFFER_ERR                 \n#undef __COPY_ERR                          \n#undef __CREATE_SUBBUFFER_ERR              \n#undef __CREATE_GL_BUFFER_ERR              \n#undef __CREATE_GL_RENDER_BUFFER_ERR       \n#undef __GET_GL_OBJECT_INFO_ERR            \n#undef __CREATE_IMAGE_ERR                  \n#undef __CREATE_GL_TEXTURE_ERR             \n#undef __IMAGE_DIMENSION_ERR               \n#undef __SET_MEM_OBJECT_DESTRUCTOR_CALLBACK_ERR \n#undef __CREATE_USER_EVENT_ERR             \n#undef __SET_USER_EVENT_STATUS_ERR         \n#undef __SET_EVENT_CALLBACK_ERR            \n#undef __WAIT_FOR_EVENTS_ERR               \n#undef __CREATE_KERNEL_ERR                 \n#undef __SET_KERNEL_ARGS_ERR               \n#undef __CREATE_PROGRAM_WITH_SOURCE_ERR    \n#undef __CREATE_PROGRAM_WITH_IL_ERR        \n#undef __CREATE_PROGRAM_WITH_BINARY_ERR    \n#undef __CREATE_PROGRAM_WITH_IL_ERR        \n#undef __CREATE_PROGRAM_WITH_BUILT_IN_KERNELS_ERR    \n#undef __BUILD_PROGRAM_ERR                 \n#undef __COMPILE_PROGRAM_ERR               \n#undef __LINK_PROGRAM_ERR                  \n#undef __CREATE_KERNELS_IN_PROGRAM_ERR     \n#undef __CREATE_COMMAND_QUEUE_WITH_PROPERTIES_ERR          \n#undef __CREATE_SAMPLER_WITH_PROPERTIES_ERR                \n#undef __SET_COMMAND_QUEUE_PROPERTY_ERR    \n#undef __ENQUEUE_READ_BUFFER_ERR           \n#undef __ENQUEUE_READ_BUFFER_RECT_ERR      \n#undef __ENQUEUE_WRITE_BUFFER_ERR          \n#undef __ENQUEUE_WRITE_BUFFER_RECT_ERR     \n#undef __ENQEUE_COPY_BUFFER_ERR            \n#undef __ENQEUE_COPY_BUFFER_RECT_ERR       \n#undef __ENQUEUE_FILL_BUFFER_ERR           \n#undef __ENQUEUE_READ_IMAGE_ERR            \n#undef __ENQUEUE_WRITE_IMAGE_ERR           \n#undef __ENQUEUE_COPY_IMAGE_ERR            \n#undef __ENQUEUE_FILL_IMAGE_ERR            \n#undef __ENQUEUE_COPY_IMAGE_TO_BUFFER_ERR  \n#undef __ENQUEUE_COPY_BUFFER_TO_IMAGE_ERR  \n#undef __ENQUEUE_MAP_BUFFER_ERR            \n#undef __ENQUEUE_MAP_IMAGE_ERR             \n#undef __ENQUEUE_UNMAP_MEM_OBJECT_ERR      \n#undef __ENQUEUE_NDRANGE_KERNEL_ERR        \n#undef __ENQUEUE_NATIVE_KERNEL             \n#undef __ENQUEUE_MIGRATE_MEM_OBJECTS_ERR   \n#undef __ENQUEUE_MIGRATE_SVM_ERR\n#undef __ENQUEUE_ACQUIRE_GL_ERR            \n#undef __ENQUEUE_RELEASE_GL_ERR            \n#undef __CREATE_PIPE_ERR             \n#undef __GET_PIPE_INFO_ERR           \n#undef __RETAIN_ERR                        \n#undef __RELEASE_ERR                       \n#undef __FLUSH_ERR                         \n#undef __FINISH_ERR                        \n#undef __VECTOR_CAPACITY_ERR               \n#undef __CREATE_SUB_DEVICES_ERR            \n#undef __CREATE_SUB_DEVICES_ERR            \n#undef __ENQUEUE_MARKER_ERR                \n#undef __ENQUEUE_WAIT_FOR_EVENTS_ERR       \n#undef __ENQUEUE_BARRIER_ERR               \n#undef __UNLOAD_COMPILER_ERR               \n#undef __CREATE_GL_TEXTURE_2D_ERR          \n#undef __CREATE_GL_TEXTURE_3D_ERR          \n#undef __CREATE_IMAGE2D_ERR                \n#undef __CREATE_IMAGE3D_ERR                \n#undef __CREATE_COMMAND_QUEUE_ERR          \n#undef __ENQUEUE_TASK_ERR                  \n#undef __CREATE_SAMPLER_ERR                \n#undef __ENQUEUE_MARKER_WAIT_LIST_ERR                \n#undef __ENQUEUE_BARRIER_WAIT_LIST_ERR               \n#undef __CLONE_KERNEL_ERR     \n#undef __GET_HOST_TIMER_ERR\n#undef __GET_DEVICE_AND_HOST_TIMER_ERR\n\n#endif //CL_HPP_USER_OVERRIDE_ERROR_STRINGS\n\n// Extensions\n#undef CL_HPP_INIT_CL_EXT_FCN_PTR_\n#undef CL_HPP_INIT_CL_EXT_FCN_PTR_PLATFORM_\n\n#if defined(CL_HPP_USE_CL_DEVICE_FISSION)\n#undef CL_HPP_PARAM_NAME_DEVICE_FISSION_\n#endif // CL_HPP_USE_CL_DEVICE_FISSION\n\n#undef CL_HPP_NOEXCEPT_\n#undef CL_HPP_DEFINE_STATIC_MEMBER_\n\n} // namespace cl\n\n#endif // CL_HPP_\n"
  },
  {
    "path": "ToUTF8/ToUTF8.cpp",
    "content": "#define WIN32_LEAN_AND_MEAN\n#include <windows.h>\n#include <iostream>\n#include <fstream>\n#include <vector>\n#include <string>\n#include <cstdlib>\n\n// Helper: Convert wide string to UTF-8 std::string.\nstd::string wstringToUtf8(const std::wstring& wstr) {\n    if (wstr.empty())\n        return std::string();\n\n    // Determine the size needed for the UTF-8 string.\n    int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.data(),\n        static_cast<int>(wstr.size()),\n        NULL, 0, NULL, NULL);\n    std::string result(size_needed, 0);\n    WideCharToMultiByte(CP_UTF8, 0, wstr.data(),\n        static_cast<int>(wstr.size()),\n        &result[0], size_needed, NULL, NULL);\n    return result;\n}\n\n// Check if text is valid UTF-8 (provided earlier).\nbool IsTextUtf8(const std::vector<char>& text)\n{\n    auto Src = text.begin();\n    const auto SrcEnd = text.end();\n    while (Src != SrcEnd)\n    {\n        int C = *(Src++);\n        int HighOne = 0; // Number of leftmost '1' bits.\n        for (int Mask = 0x80; Mask != 0 && (C & Mask) != 0; Mask >>= 1)\n            HighOne++;\n        if (HighOne == 1 || HighOne > 4)\n            return false;\n        while (--HighOne > 0)\n            if (Src == SrcEnd || (*(Src++) & 0xc0) != 0x80)\n                return false;\n    }\n    return true;\n}\n\n// Enumeration of supported encodings.\nenum class Encoding {\n    Unknown,\n    UTF8BOM,\n    UTF8,\n    UTF16LE,\n    UTF16BE,\n    UTF16,\n    ANSI\n};\n\n// Read the entire file into a vector of char.\nstd::vector<char> readFile(const wchar_t* filename) {\n    std::ifstream in(filename, std::ios::binary);\n    if (!in) {\n        std::cerr << \"Error opening input file: \" << filename << std::endl;\n        exit(EXIT_FAILURE);\n    }\n    return std::vector<char>(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>());\n}\n\n// Detect encoding based on BOM; if no BOM, use IsTextUtf8 to decide if UTF-8.\nEncoding detectEncoding(const std::vector<char>& buffer) {\n    if (buffer.size() >= 3 &&\n        static_cast<unsigned char>(buffer[0]) == 0xEF &&\n        static_cast<unsigned char>(buffer[1]) == 0xBB &&\n        static_cast<unsigned char>(buffer[2]) == 0xBF)\n    {\n        return Encoding::UTF8BOM;\n    }\n    if (buffer.size() >= 2 &&\n        static_cast<unsigned char>(buffer[0]) == 0xFF &&\n        static_cast<unsigned char>(buffer[1]) == 0xFE)\n    {\n        return Encoding::UTF16LE;\n    }\n    if (buffer.size() >= 2 &&\n        static_cast<unsigned char>(buffer[0]) == 0xFE &&\n        static_cast<unsigned char>(buffer[1]) == 0xFF)\n    {\n        return Encoding::UTF16BE;\n    }\n    // No BOM: if valid UTF-8, assume UTF-8; otherwise ANSI.\n    if (IsTextUtf8(buffer))\n        return Encoding::UTF8;\n\n    // Otherwise, use IsTextUnicode to get a hint if it might be UTF-16\n    BOOL isUnicode = FALSE;\n    // Note: You can pass in a pointer to a flag if you need additional output.\n    if (IsTextUnicode(buffer.data(), static_cast<int>(buffer.size()), &isUnicode) && isUnicode) {\n        // For simplicity, assume little-endian if Unicode is detected.\n        return Encoding::UTF16;\n    }\n    return Encoding::ANSI;\n}\n\n// Convert input buffer to a wide string.\nstd::wstring convertToWideString(const std::vector<char>& buffer, Encoding enc) {\n    if (enc == Encoding::UTF8BOM || enc == Encoding::UTF8) {\n        int bomSize = (enc == Encoding::UTF8BOM) ? 3 : 0;\n        int wideSize = MultiByteToWideChar(CP_UTF8, 0, buffer.data() + bomSize,\n            static_cast<int>(buffer.size() - bomSize), NULL, 0);\n        std::wstring wstr(wideSize, L'\\0');\n        MultiByteToWideChar(CP_UTF8, 0, buffer.data() + bomSize,\n            static_cast<int>(buffer.size() - bomSize),\n            &wstr[0], wideSize);\n        return wstr;\n    }\n    else if (enc == Encoding::UTF16LE) {\n        int wcharCount = (static_cast<int>(buffer.size()) - 2) / 2;\n        const wchar_t* start = reinterpret_cast<const wchar_t*>(buffer.data() + 2);\n        return std::wstring(start, wcharCount);\n    }\n    else if (enc == Encoding::UTF16) {\n        int wcharCount = static_cast<int>(buffer.size()) / 2;\n        const wchar_t* start = reinterpret_cast<const wchar_t*>(buffer.data());\n        return std::wstring(start, wcharCount);\n    }\n    else if (enc == Encoding::UTF16BE) {\n        int wcharCount = (static_cast<int>(buffer.size()) - 2) / 2;\n        std::wstring wstr;\n        wstr.resize(wcharCount);\n        const unsigned char* data = reinterpret_cast<const unsigned char*>(buffer.data() + 2);\n        for (int i = 0; i < wcharCount; i++) {\n            wstr[i] = static_cast<wchar_t>(data[2 * i + 1] | (data[2 * i] << 8));\n        }\n        return wstr;\n    }\n    else { // ANSI\n        int wideSize = MultiByteToWideChar(CP_ACP, 0, buffer.data(),\n            static_cast<int>(buffer.size()), NULL, 0);\n        std::wstring wstr(wideSize, L'\\0');\n        MultiByteToWideChar(CP_ACP, 0, buffer.data(),\n            static_cast<int>(buffer.size()), &wstr[0], wideSize);\n        return wstr;\n    }\n}\n\n// Convert a wide string to a UTF-8 std::string.\nstd::string convertWideToUTF8(const std::wstring& wstr) {\n    int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.data(),\n        static_cast<int>(wstr.size()), NULL, 0, NULL, NULL);\n    std::string result(size_needed, '\\0');\n    WideCharToMultiByte(CP_UTF8, 0, wstr.data(),\n        static_cast<int>(wstr.size()),\n        &result[0], size_needed, NULL, NULL);\n    return result;\n}\n\n// Main function using a wide-character entry point.\nint wmain(int argc, wchar_t* argv[])\n{\n    if (argc < 3) {\n        std::wcerr << L\"Usage: ToUTF8.exe <inputfile> <outputfile>\" << std::endl;\n        return EXIT_FAILURE;\n    }\n\n    // Read the entire input file.\n    std::vector<char> buffer = readFile(argv[1]);\n\n    // Detect encoding.\n    Encoding encoding = detectEncoding(buffer);\n\n    std::wcout << L\"Detected encoding: \";\n    switch (encoding) {\n    case Encoding::UTF8BOM:     std::wcout << L\"UTF-8 BOM\"; break;\n    case Encoding::UTF8:     std::wcout << L\"UTF-8\"; break;\n    case Encoding::UTF16LE:   std::wcout << L\"UTF-16 LE\"; break;\n    case Encoding::UTF16:   std::wcout << L\"UTF-16\"; break;\n    case Encoding::UTF16BE:   std::wcout << L\"UTF-16 BE\"; break;\n    case Encoding::ANSI:      std::wcout << L\"ANSI\"; break;\n    default:                  std::wcout << L\"Unknown\"; break;\n    }\n    std::wcout << std::endl;\n\n    // Convert the input file content to a wide string.\n    std::wstring wideContent = convertToWideString(buffer, encoding);\n\n    // Convert the wide string to UTF-8.\n    std::string utf8Content = convertWideToUTF8(wideContent);\n\n    // Write the UTF-8 output to the output file, and write the UTF-8 BOM first.\n    std::ofstream outFile(argv[2], std::ios::binary);\n    if (!outFile) {\n        std::wcerr << L\"Error creating output file: \" << argv[2] << std::endl;\n        return EXIT_FAILURE;\n    }\n\n    // Write UTF-8 BOM: 0xEF, 0xBB, 0xBF.\n    const unsigned char bom[3] = { 0xEF, 0xBB, 0xBF };\n    outFile.write(reinterpret_cast<const char*>(bom), sizeof(bom));\n\n    // Write the converted UTF-8 text.\n    outFile.write(utf8Content.data(), utf8Content.size());\n    outFile.close();\n\n    std::cout << \"Conversion to UTF-8 with BOM completed successfully.\" << std::endl;\n    return EXIT_SUCCESS;\n}\n"
  },
  {
    "path": "ToUTF8/ToUTF8.vcxproj",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>17.0</VCProjectVersion>\n    <Keyword>Win32Proj</Keyword>\n    <ProjectGuid>{f082ef32-a1d0-48b9-9af1-dc56178ede92}</ProjectGuid>\n    <RootNamespace>ToUTF8</RootNamespace>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <SDLCheck>true</SDLCheck>\n      <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <ConformanceMode>true</ConformanceMode>\n    </ClCompile>\n    <Link>\n      <SubSystem>Console</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"ToUTF8.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "ToUTF8/ToUTF8.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"ToUTF8.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "audio/AudioPitchDecorator.cpp",
    "content": "#include \"AudioPitchDecorator.h\"\n\n#include \"smbPitchShift.h\"\n\n#include <algorithm>\n#include <utility>\n\nAudioPitchDecorator::AudioPitchDecorator(std::unique_ptr<IAudioPlayer> player\n    , std::function<float()> getPitchShift)\n    : m_player(std::move(player))\n    , m_getPitchShift(std::move(getPitchShift))\n{\n}\n\nAudioPitchDecorator::~AudioPitchDecorator() = default;\n\nvoid AudioPitchDecorator::SetCallback(IAudioPlayerCallback * callback)\n{\n    m_player->SetCallback(callback);\n}\n\nvoid AudioPitchDecorator::InitializeThread()\n{\n    m_player->InitializeThread();\n}\n\nvoid AudioPitchDecorator::DeinitializeThread()\n{\n    m_player->DeinitializeThread();\n}\n\nvoid AudioPitchDecorator::WaveOutReset()\n{\n    m_player->WaveOutReset();\n    for (auto& v : m_smbPitchShifts)\n        v.reset();\n}\n\nvoid AudioPitchDecorator::Close()\n{\n    m_player->Close();\n}\n\nbool AudioPitchDecorator::Open(int bytesPerSample, int channels, int * samplesPerSec)\n{\n    if (!m_player->Open(bytesPerSample, channels, samplesPerSec))\n        return false;\n\n    m_bytesPerSample = bytesPerSample;\n    m_samplesPerSec = *samplesPerSec;\n    m_smbPitchShifts.resize(channels);\n    for (auto& v : m_smbPitchShifts)\n        v.reset();\n\n    return true;\n}\n\nvoid AudioPitchDecorator::SetVolume(double volume)\n{\n    m_player->SetVolume(volume);\n}\n\ndouble AudioPitchDecorator::GetVolume() const\n{\n    return m_player->GetVolume();\n}\n\nvoid AudioPitchDecorator::WaveOutPause()\n{\n    m_player->WaveOutPause();\n}\n\nvoid AudioPitchDecorator::WaveOutRestart()\n{\n    m_player->WaveOutRestart();\n}\n\nbool AudioPitchDecorator::WriteAudio(uint8_t * write_data, int64_t write_size)\n{\n    const auto pitchShift = m_getPitchShift();\n    if (pitchShift != 1. && m_bytesPerSample == 2)\n    {\n        const auto numSamples = (write_size / m_bytesPerSample) / m_smbPitchShifts.size();\n        if (m_buffer.size() < numSamples)\n            m_buffer.resize(numSamples);\n        int16_t* const intData = (int16_t*)write_data;\n        for (int i = 0; i < m_smbPitchShifts.size(); ++i)\n        {\n            for (size_t j = 0; j < numSamples; ++j)\n            {\n                m_buffer[j] = intData[j * m_smbPitchShifts.size() + i] / 32768.;\n            }\n            m_smbPitchShifts[i].smbPitchShift(\n                pitchShift, numSamples, 4096, 16, m_samplesPerSec, m_buffer.data(), m_buffer.data());\n            for (size_t j = 0; j < numSamples; ++j)\n            {\n                // decrease level to avoid clipping distortions\n                intData[j * m_smbPitchShifts.size() + i] = std::clamp(m_buffer[j], -2.f, 2.f) * (32767. / 2);\n            }\n        }\n    }\n    else\n    {\n        for (auto& v : m_smbPitchShifts)\n            v.reset();\n    }\n    return m_player->WriteAudio(write_data, write_size);\n}\n"
  },
  {
    "path": "audio/AudioPitchDecorator.h",
    "content": "#pragma once\n\n#include \"../video/audioplayer.h\"\n\n#include <functional>\n#include <memory>\n#include <vector>\n\nclass CSmbPitchShift;\n\nclass AudioPitchDecorator :\n    public IAudioPlayer\n{\npublic:\n    AudioPitchDecorator(std::unique_ptr<IAudioPlayer> player, \n        std::function<float()> getPitchShift);\n    ~AudioPitchDecorator();\n\n    AudioPitchDecorator(const AudioPitchDecorator&) = delete;\n    AudioPitchDecorator& operator =(const AudioPitchDecorator&) = delete;\n\n    // Inherited via IAudioPlayer\n    void SetCallback(IAudioPlayerCallback * callback) override;\n    void InitializeThread() override;\n    void DeinitializeThread() override;\n    void WaveOutReset() override;\n    void Close() override;\n    bool Open(int bytesPerSample, int channels, int * samplesPerSec) override;\n    void SetVolume(double volume) override;\n    double GetVolume() const override;\n    void WaveOutPause() override;\n    void WaveOutRestart() override;\n    bool WriteAudio(uint8_t * write_data, int64_t write_size) override;\n\nprivate:\n    std::unique_ptr<IAudioPlayer> m_player;\n    std::function<float()> m_getPitchShift;\n    std::vector<CSmbPitchShift> m_smbPitchShifts;\n\n    std::vector<float> m_buffer;\n\n    int m_bytesPerSample{};\n    int m_samplesPerSec{};\n};\n\n"
  },
  {
    "path": "audio/AudioPlayerImpl.cpp",
    "content": "#include \"AudioPlayerImpl.h\"\n\n#include <malloc.h>\n\n\nnamespace {\n\nenum \n{\n    BLOCK_SIZE = 4096,\n    BLOCK_COUNT  = 4,\n};\n\nWAVEHDR* allocateBlocks(int size, int count)\n{\n    const size_t totalBufferSize = (sizeof(WAVEHDR) + size) * count;\n    // allocate memory for the entire set in one step\n    char* buffer = (char*) calloc(totalBufferSize, 1);\n\n    // and set up the pointers to each bit\n    WAVEHDR* blocks = (WAVEHDR*)buffer;\n    buffer += sizeof(WAVEHDR) * count;\n    for (int i = 0; i < count; ++i)\n    {\n        blocks[i].dwBufferLength = size;\n        blocks[i].lpData = buffer;\n        buffer += size;\n    }\n    return blocks;\n}\n\nvoid freeBlocks(WAVEHDR* blockArray)\n{\n    free(blockArray);\n}\n\n} // namespace\n\nAudioPlayerImpl::AudioPlayerImpl()\n    : m_callback(nullptr)\n    , m_waveOutput(NULL)\n    , m_waveBlocks(nullptr)\n    , m_evtHasFreeBlocks(CreateEvent(NULL, FALSE, FALSE, NULL))\n    , m_bytesPerSecond(0)\n{\n}\n\n\nAudioPlayerImpl::~AudioPlayerImpl()\n{\n    CloseHandle(m_evtHasFreeBlocks);\n}\n\nvoid AudioPlayerImpl::InitializeThread()\n{\n    ATLTRACE(\"Old audio thread priority = %d\\n\", GetThreadPriority(GetCurrentThread()));\n    ATLVERIFY(SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL));\n}\n\nvoid AudioPlayerImpl::DeinitializeThread()\n{\n}\n\nvoid AudioPlayerImpl::WaveOutReset()\n{\n    waveOutReset(m_waveOutput);\n}\n\nvoid AudioPlayerImpl::Close()\n{\n    if (m_waveOutput != NULL)\n    {\n        waveOutReset(m_waveOutput);\n        waveOutClose(m_waveOutput);\n    }\n\n    if (m_waveBlocks)\n    {\n        // unprepare any blocks that are still prepared\n        for (int i = 0; i < m_waveFreeBlockCount; ++i)\n        {\n            if (m_waveBlocks[i].dwFlags & WHDR_PREPARED)\n            {\n                waveOutUnprepareHeader(m_waveOutput, &m_waveBlocks[i], sizeof(WAVEHDR));\n            }\n        }\n\n        freeBlocks(m_waveBlocks);\n    }\n\n    m_waveOutput = NULL;\n    m_waveBlocks = nullptr;\n    m_waveFreeBlockCount = BLOCK_COUNT;\n    ResetEvent(m_evtHasFreeBlocks);\n    m_waveCurrentBlock = 0;\n}\n\nbool AudioPlayerImpl::Open(int bytesPerSample, int channels, int* samplesPerSec)\n{\n    m_waveBlocks = allocateBlocks(BLOCK_SIZE, BLOCK_COUNT);\n    m_waveFreeBlockCount = BLOCK_COUNT;\n    m_waveCurrentBlock = 0;\n\n    WAVEFORMATEX waveFormat = {};\n\n    waveFormat.wBitsPerSample = bytesPerSample << 3;\n    waveFormat.nSamplesPerSec = *samplesPerSec;\n    waveFormat.nChannels = channels;\n\n    waveFormat.cbSize = 0; // size of _extra_ info\n    waveFormat.wFormatTag = WAVE_FORMAT_PCM;\n    waveFormat.nBlockAlign = (waveFormat.wBitsPerSample >> 3) * waveFormat.nChannels;\n    waveFormat.nAvgBytesPerSec = waveFormat.nBlockAlign * waveFormat.nSamplesPerSec;\n    m_bytesPerSecond = waveFormat.nAvgBytesPerSec;\n\n    ATLTRACE(\"Bits per sample = %d\\n\", waveFormat.wBitsPerSample);\n    ATLTRACE(\"Samples per second = %d\\n\", waveFormat.nSamplesPerSec);\n    ATLTRACE(\"Channels = %d\\n\", waveFormat.nChannels);\n    ATLTRACE(\"Block align = %d\\n\", waveFormat.nBlockAlign);\n    ATLTRACE(\"Average bit rate = %d\\n\", waveFormat.nAvgBytesPerSec);\n\n    if (waveOutOpen(\n        &m_waveOutput,\n        WAVE_MAPPER,\n        &waveFormat,\n        (DWORD_PTR)waveOutProc,\n        (DWORD_PTR)this,\n        CALLBACK_FUNCTION\n        ) != MMSYSERR_NOERROR)\n    {\n        ATLTRACE(\"Unable to open WAVE_MAPPER device.\\n\");\n        return false;\n    }\n\n    return true;\n}\n\nvoid AudioPlayerImpl::SetVolume(double volume)\n{\n    WORD vol = (WORD)(volume * 0xFFFF);\n    // Left and right channels\n    waveOutSetVolume(m_waveOutput, (DWORD)(vol << 16 | vol & 0xFFFF));\n}\n\ndouble AudioPlayerImpl::GetVolume() const\n{\n    const double point = 1. / 0xFFFF;\n    DWORD volume = 0;\n    waveOutGetVolume(m_waveOutput, &volume);\n    return (volume & 0xFFFF) * point;\n}\n\nvoid AudioPlayerImpl::WaveOutPause()\n{\n    waveOutPause(m_waveOutput);\n}\n\nvoid AudioPlayerImpl::WaveOutRestart()\n{\n    waveOutRestart(m_waveOutput);\n}\n\nbool AudioPlayerImpl::WriteAudio(uint8_t* write_data, int64_t write_size)\n{\n    if (!m_waveOutput)\n        return false;\n\n    WAVEHDR* current = &m_waveBlocks[m_waveCurrentBlock];\n    while (write_size > 0)\n    {\n        // fill block partially and wait for the next writeAudio call\n        if (write_size < (int)(BLOCK_SIZE - current->dwUser))\n        {\n            memcpy(current->lpData + current->dwUser, write_data, (size_t)write_size);\n            current->dwUser += (DWORD_PTR)write_size;\n            break;\n        }\n\n        // fill block completely and play it\n        const int remain = BLOCK_SIZE - current->dwUser;\n        memcpy(current->lpData + current->dwUser, write_data, remain);\n\n        write_size -= remain;\n        write_data += remain;\n\n        ATLASSERT(current->dwBufferLength == BLOCK_SIZE);\n        if (current->dwFlags & WHDR_PREPARED || waveOutPrepareHeader(m_waveOutput, current, sizeof(WAVEHDR)) == MMSYSERR_NOERROR)\n        {\n            if (-1 == InterlockedDecrement(&m_waveFreeBlockCount))\n            {\n                WaitForSingleObject(m_evtHasFreeBlocks, INFINITE);\n            }\n\n            MMRESULT isOutWritten = waveOutWrite(m_waveOutput, current, sizeof(WAVEHDR));\n            if (isOutWritten != MMSYSERR_NOERROR)\n            {\n                InterlockedIncrement(&m_waveFreeBlockCount);\n            }\n        }\n\n        // point to the next block\n        ++m_waveCurrentBlock;\n        m_waveCurrentBlock %= BLOCK_COUNT;\n        current = &m_waveBlocks[m_waveCurrentBlock];\n        current->dwUser = 0;\n    }\n\n    return true;\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\n\nvoid CALLBACK AudioPlayerImpl::waveOutProc(HWAVEOUT, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR, DWORD_PTR)\n{\n    // ignore calls that occur due to openining and closing the device.\n    if (uMsg == WOM_DONE)\n    {\n        // pointer to free block counter\n        auto waveArgs = reinterpret_cast<AudioPlayerImpl*>(dwInstance);\n\n        if (0 == InterlockedIncrement(&waveArgs->m_waveFreeBlockCount))\n        {\n            SetEvent(waveArgs->m_evtHasFreeBlocks);\n        }\n\n        // count audio pts\n        const double frame_clock = (double)BLOCK_SIZE / waveArgs->m_bytesPerSecond;\n        waveArgs->m_callback->AppendFrameClock(frame_clock);\n    }\n}\n"
  },
  {
    "path": "audio/AudioPlayerImpl.h",
    "content": "#pragma once\n\n#include \"../video/audioplayer.h\"\n\n#include <atlbase.h>\n#include <mmsystem.h>\n\nclass AudioPlayerImpl :\n    public IAudioPlayer\n{\npublic:\n    AudioPlayerImpl();\n    ~AudioPlayerImpl() override;\n\n    AudioPlayerImpl(const AudioPlayerImpl&) = delete;\n    AudioPlayerImpl& operator=(const AudioPlayerImpl&) = delete;\n\n    void SetCallback(IAudioPlayerCallback* callback) override\n    {\n        m_callback = callback;\n    }\n\n    void InitializeThread() override;\n    void DeinitializeThread() override;\n\n    void WaveOutReset() override;\n\n    void Close() override;\n    bool Open(int bytesPerSample, int channels, int* samplesPerSec) override;\n\n    void SetVolume(double volume) override;\n    double GetVolume() const override;\n\n    void WaveOutPause() override;\n    void WaveOutRestart() override;\n\n    bool WriteAudio(uint8_t* write_data, int64_t write_size) override;\n\nprivate:\n    IAudioPlayerCallback* m_callback;\n\n    HWAVEOUT\t\t\tm_waveOutput;\n\n    static void CALLBACK waveOutProc(HWAVEOUT, UINT, DWORD_PTR, DWORD_PTR, DWORD_PTR);\n\n    WAVEHDR*\t\t\tm_waveBlocks;\n    volatile long\t\tm_waveFreeBlockCount {};\n    HANDLE\t\t\t\tm_evtHasFreeBlocks;\n    int\t\t\t\t\tm_waveCurrentBlock {};\n\n    int\t\t\t\t\tm_bytesPerSecond;\n};\n\n"
  },
  {
    "path": "audio/AudioPlayerWasapi.cpp",
    "content": "#include \"AudioPlayerWasapi.h\"\n\n#include <Audioclient.h>\n#include <MMDeviceAPI.h>\n#include <Avrt.h>\n\n#include <string>\n#include <atlstr.h>\n\nnamespace {\n\nHMODULE GetAvrtHandle()\n{\n    static HMODULE avrtHandle = LoadLibrary(_T(\"Avrt.dll\"));\n    return avrtHandle;\n}\n\n}\n\n// https://chromium.googlesource.com/chromium/src/media/+/master/audio/win/core_audio_util_win.cc\nnamespace CoreAudioUtil\n{\n\n    CComPtr<IMMDeviceEnumerator> CreateDeviceEnumeratorInternal(\n        bool allow_reinitialize) {\n        CComPtr<IMMDeviceEnumerator> device_enumerator;\n        HRESULT hr = device_enumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator),\n            NULL, CLSCTX_INPROC_SERVER);\n        if (hr == CO_E_NOTINITIALIZED && allow_reinitialize) {\n            ATLTRACE(\"CoCreateInstance fails with CO_E_NOTINITIALIZED\\n\");\n            // We have seen crashes which indicates that this method can in fact\n            // fail with CO_E_NOTINITIALIZED in combination with certain 3rd party\n            // modules. Calling CoInitializeEx is an attempt to resolve the reported\n            // issues. See http://crbug.com/378465 for details.\n            hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);\n            if (SUCCEEDED(hr)) {\n                hr = device_enumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator),\n                    NULL, CLSCTX_INPROC_SERVER);\n            }\n        }\n        return device_enumerator;\n    }\n\n    CComPtr<IMMDeviceEnumerator> CreateDeviceEnumerator() {\n        //ASSERT(IsSupported());\n        auto device_enumerator = CreateDeviceEnumeratorInternal(true);\n        ATLASSERT(device_enumerator);\n        return device_enumerator;\n    }\n\n    CComPtr<IMMDevice> CreateDefaultDevice(EDataFlow data_flow,\n        ERole role) {\n        //ASSERT(IsSupported());\n        CComPtr<IMMDevice> endpoint_device;\n        // Create the IMMDeviceEnumerator interface.\n        auto device_enumerator = CreateDeviceEnumerator();\n        if (!device_enumerator)\n            return endpoint_device;\n        // Retrieve the default audio endpoint for the specified data-flow\n        // direction and role.\n        HRESULT hr = device_enumerator->GetDefaultAudioEndpoint(\n            data_flow, role, &endpoint_device);\n        if (FAILED(hr)) {\n            ATLTRACE(\"IMMDeviceEnumerator::GetDefaultAudioEndpoint: %x\\n\", hr);\n            return endpoint_device;\n        }\n\n        // Verify that the audio endpoint device is active, i.e., that the audio\n        // adapter that connects to the endpoint device is present and enabled.\n        DWORD state = DEVICE_STATE_DISABLED;\n        hr = endpoint_device->GetState(&state);\n        if (SUCCEEDED(hr)) {\n            if (!(state & DEVICE_STATE_ACTIVE)) {\n                ATLTRACE(\"Selected endpoint device is not active\\n\");\n                endpoint_device.Release();\n            }\n        }\n        return endpoint_device;\n    }\n\n    CComPtr<IMMDevice> CreateDevice(\n        const std::string& device_id) {\n        //ASSERT(IsSupported());\n        CComPtr<IMMDevice> endpoint_device;\n        // Create the IMMDeviceEnumerator interface.\n        auto device_enumerator = CreateDeviceEnumerator();\n        if (!device_enumerator)\n            return endpoint_device;\n        // Retrieve an audio device specified by an endpoint device-identification\n        // string.\n        HRESULT hr = device_enumerator->GetDevice(CAtlStringW(device_id.c_str()), &endpoint_device);\n        if (FAILED(hr)) {\n            ATLTRACE(\"IMMDeviceEnumerator::GetDevice: %x\\n\", hr);\n        }\n        return endpoint_device;\n    }\n\n    CComPtr<IAudioClient> CreateClient(\n        IMMDevice* audio_device) {\n        //ASSERT(IsSupported());\n        // Creates and activates an IAudioClient COM object given the selected\n        // endpoint device.\n        CComPtr<IAudioClient> audio_client;\n        HRESULT hr = audio_device->Activate(__uuidof(IAudioClient),\n            CLSCTX_INPROC_SERVER,\n            NULL,\n            (void**)&audio_client);\n        if (FAILED(hr)) {\n            ATLTRACE(\"IMMDevice::Activate: %x\\n\", hr);\n        }\n\n        return audio_client;\n    }\n\n\n    CComPtr<IAudioClient> CreateDefaultClient(\n    EDataFlow data_flow, ERole role) {\n        //ASSERT(IsSupported());\n        auto default_device = CreateDefaultDevice(data_flow, role);\n        if (!default_device)\n            return {};\n        return CreateClient(default_device);\n    }\n\n\n    CComPtr<IAudioClient> CreateClient(\n        const std::string& device_id, EDataFlow data_flow, ERole role) {\n        if (device_id.empty())\n            return CreateDefaultClient(data_flow, role);\n        auto device = CreateDevice(device_id);\n        if (!device)\n            return {};\n        return CreateClient(device);\n    }\n\n    HRESULT GetSharedModeMixFormat(\n        IAudioClient* client, WAVEFORMATPCMEX* format) {\n        //ASSERT(IsSupported());\n        CComHeapPtr<WAVEFORMATPCMEX> format_pcmex;\n        HRESULT hr = client->GetMixFormat(\n            reinterpret_cast<WAVEFORMATEX**>(&format_pcmex));\n        if (FAILED(hr))\n            return hr;\n        size_t bytes = sizeof(WAVEFORMATEX) + format_pcmex->Format.cbSize;\n        ATLASSERT(bytes == sizeof(WAVEFORMATPCMEX));\n        memcpy(format, format_pcmex, bytes);\n        return hr;\n    }\n\n    DWORD GetChannelConfig(const std::string& device_id,\n        EDataFlow data_flow) {\n        auto client = CreateClient(device_id, data_flow, eConsole);\n        WAVEFORMATPCMEX format = { 0 };\n        if (!client || FAILED(GetSharedModeMixFormat(client, &format)))\n            return 0;\n        return format.dwChannelMask;\n    }\n\n\n    HRESULT SharedModeInitialize(\n        IAudioClient* client, const WAVEFORMATPCMEX* format, HANDLE event_handle,\n        unsigned int* endpoint_buffer_size, const GUID* session_guid) {\n        //ASSERT(IsSupported());\n        // Use default flags (i.e, dont set AUDCLNT_STREAMFLAGS_NOPERSIST) to\n        // ensure that the volume level and muting state for a rendering session\n        // are persistent across system restarts. The volume level and muting\n        // state for a capture session are never persistent.\n        DWORD stream_flags = 0;\n        // Enable event-driven streaming if a valid event handle is provided.\n        // After the stream starts, the audio engine will signal the event handle\n        // to notify the client each time a buffer becomes ready to process.\n        // Event-driven buffering is supported for both rendering and capturing.\n        // Both shared-mode and exclusive-mode streams can use event-driven buffering.\n        bool use_event = (event_handle != NULL &&\n            event_handle != INVALID_HANDLE_VALUE);\n        if (use_event)\n            stream_flags |= AUDCLNT_STREAMFLAGS_EVENTCALLBACK;\n        ATLTRACE(\"stream_flags: 0x%x\\n\", stream_flags);\n        // Initialize the shared mode client for minimal delay.\n        HRESULT hr = client->Initialize(AUDCLNT_SHAREMODE_SHARED,\n            stream_flags,\n            100 * 10000,\n            0,\n            reinterpret_cast<const WAVEFORMATEX*>(format),\n            session_guid);\n        if (FAILED(hr)) {\n            ATLTRACE(\"IAudioClient::Initialize: %x\\n\", hr);\n            return hr;\n        }\n        if (use_event) {\n            hr = client->SetEventHandle(event_handle);\n            if (FAILED(hr)) {\n                ATLTRACE(\"IAudioClient::SetEventHandle: %x\\n\", hr);\n                return hr;\n            }\n        }\n        UINT32 buffer_size_in_frames = 0;\n        hr = client->GetBufferSize(&buffer_size_in_frames);\n        if (FAILED(hr)) {\n            ATLTRACE(\"IAudioClient::GetBufferSize: %x\\n\", hr);\n            return hr;\n        }\n        *endpoint_buffer_size = buffer_size_in_frames;\n        ATLTRACE(\"endpoint buffer size: %d\\n\", buffer_size_in_frames);\n\n        return hr;\n    }\n\n    CComPtr<IAudioRenderClient> CreateRenderClient(\n        IAudioClient* client) {\n        //ASSERT(IsSupported());\n        // Get access to the IAudioRenderClient interface. This interface\n        // enables us to write output data to a rendering endpoint buffer.\n        CComPtr<IAudioRenderClient> audio_render_client;\n        HRESULT hr = client->GetService(__uuidof(IAudioRenderClient),\n            (void**) &audio_render_client);\n        if (FAILED(hr)) {\n            ATLTRACE(\"IAudioClient::GetService: %x\\n\", hr);\n            return CComPtr<IAudioRenderClient>();\n        }\n        return audio_render_client;\n    }\n\n} // namespace CoreAudioUtil\n\nconst GUID kCommunicationsSessionId = {\n    0xbe39af4f, 0x87c, 0x423f, { 0x93, 0x3, 0x23, 0x4e, 0xc1, 0xe5, 0xb8, 0xee }\n};\n\nAudioPlayerWasapi::AudioPlayerWasapi()\n    : m_callback(nullptr)\n    , m_hAudioSamplesRenderEvent(CreateEvent(NULL, FALSE, FALSE, NULL))\n    , m_BufferSize(0)\n    , m_FrameSize(0)\n    , m_samplesPerSec(0)\n    , m_mmcssHandle(NULL)\n    , m_coUnitialize(false)\n{\n\n}\n\nAudioPlayerWasapi::~AudioPlayerWasapi()\n{\n    CloseHandle(m_hAudioSamplesRenderEvent);\n}\n\nbool AudioPlayerWasapi::Open(int bytesPerSample, int channels, int* samplesPerSec)\n{\n    const ERole device_role_ = eConsole;\n\n    // Will be set to true if we ended up opening the default communications device.\n    const bool communications_device = (device_role_ == eCommunications);\n\n    // Create an IAudioClient interface for the default rendering IMMDevice.\n    auto audio_client = CoreAudioUtil::CreateDefaultClient(eRender, device_role_);\n    if (!audio_client)\n        return false;\n\n    WAVEFORMATPCMEX format_ = {};\n\n    HRESULT hr = CoreAudioUtil::GetSharedModeMixFormat(audio_client, &format_);\n    if (FAILED(hr))\n        return false;\n\n    if (format_.Format.nSamplesPerSec != 0)\n    {\n        *samplesPerSec = format_.Format.nSamplesPerSec;\n    }\n\n    // Begin with the WAVEFORMATEX structure that specifies the basic format.\n    WAVEFORMATEX* format = &format_.Format;\n    format->wFormatTag = WAVE_FORMAT_EXTENSIBLE;\n    format->nChannels = channels;\n    format->nSamplesPerSec = *samplesPerSec;\n    format->wBitsPerSample = bytesPerSample << 3;\n    format->nBlockAlign = (format->wBitsPerSample / 8) * format->nChannels;\n    format->nAvgBytesPerSec = format->nSamplesPerSec * format->nBlockAlign;\n    format->cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);\n    m_FrameSize = format->nBlockAlign;\n\n    m_samplesPerSec = *samplesPerSec;\n\n    // Add the parts which are unique to WAVE_FORMAT_EXTENSIBLE.\n    format_.Samples.wValidBitsPerSample = bytesPerSample << 3; //params.bits_per_sample();\n    //format_.dwChannelMask = CoreAudioUtil::GetChannelConfig(std::string(), eRender);\n    format_.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;\n\n    // Initialize the audio stream between the client and the device in shared\n    // mode and using event-driven buffer handling.\n    hr = CoreAudioUtil::SharedModeInitialize(\n        audio_client, &format_, m_hAudioSamplesRenderEvent,\n        &m_BufferSize,\n        communications_device ? &kCommunicationsSessionId : NULL);\n    if (FAILED(hr))\n        return false;\n\n    // Create an IAudioRenderClient client for an initialized IAudioClient.\n    // The IAudioRenderClient interface enables us to write output data to\n    // a rendering endpoint buffer.\n    auto audio_render_client = CoreAudioUtil::CreateRenderClient(audio_client);\n    if (!audio_render_client)\n        return false;\n    // Store valid COM interfaces.\n    m_AudioClient = audio_client;\n    m_RenderClient = audio_render_client;\n\n    hr = m_AudioClient->GetService(__uuidof(ISimpleAudioVolume), (void**)&m_SimpleAudioVolume);\n\n    m_AudioClient->Start();\n\n    return true;\n}\n\nbool AudioPlayerWasapi::WriteAudio(uint8_t* write_data, int64_t write_size)\n{\n    if (!m_AudioClient || !m_RenderClient)\n    {\n        return false;\n    }\n\n    while (write_size > 0)\n    {\n        //  We need to provide the next buffer of samples to the audio renderer.\n        //  We want to find out how much of the buffer *isn't* available (is padding).\n        UINT32 padding;\n        HRESULT hr = m_AudioClient->GetCurrentPadding(&padding);\n        if (FAILED(hr))\n        {\n            ATLTRACE(\"Unable to get padding: %x\\n\", hr);\n            return false;\n        }\n\n        UINT32 framesAvailable = m_BufferSize - padding;\n\n        if (framesAvailable != 0)\n        {\n            const auto remain = min(write_size, framesAvailable * m_FrameSize);\n\n            UINT32 framesToWrite = UINT32(remain / m_FrameSize);\n            BYTE *pData;\n            hr = m_RenderClient->GetBuffer(framesToWrite, &pData);\n            if (SUCCEEDED(hr))\n            {\n                //  Copy data from the render buffer to the output buffer and bump our render pointer.\n                memcpy(pData, write_data, framesToWrite * m_FrameSize);\n                hr = m_RenderClient->ReleaseBuffer(framesToWrite, 0);\n                if (!SUCCEEDED(hr))\n                {\n                    ATLTRACE(\"Unable to release buffer: %x\\n\", hr);\n                }\n\n                // count audio pts\n                const double frame_clock = (double)framesToWrite / m_samplesPerSec;\n                m_callback->AppendFrameClock(frame_clock);\n            }\n            else\n            {\n                ATLTRACE(\"Unable to get buffer: %x\\n\", hr);\n            }\n            write_size -= remain;\n            write_data += remain;\n        }\n        if (write_size > 0)\n        {\n            WaitForSingleObject(m_hAudioSamplesRenderEvent, INFINITE);\n        }\n\n    }\n\n    return true;\n}\n\n#define AVRT_FUNC_PTR(name) \\\n    static decltype(name)* name##Ptr = (decltype(name)*)GetProcAddress(avrtHandle, #name)\n\nvoid AudioPlayerWasapi::InitializeThread()\n{\n    HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);\n    m_coUnitialize = (S_OK == hr);\n    if (FAILED(hr))\n    {\n        ATLTRACE(\"Unable to initialize COM in render thread: %x\\n\", hr);\n    }\n\n    ATLTRACE(\"Old audio thread priority = %d\\n\", GetThreadPriority(GetCurrentThread()));\n    ATLVERIFY(SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL));\n\n    if (auto avrtHandle = GetAvrtHandle())\n    {\n        DWORD mmcssTaskIndex = 0;\n        AVRT_FUNC_PTR(AvSetMmThreadCharacteristicsW);\n        if (AvSetMmThreadCharacteristicsWPtr)\n        {\n            m_mmcssHandle = AvSetMmThreadCharacteristicsWPtr(L\"Pro Audio\", &mmcssTaskIndex);\n            if (m_mmcssHandle == NULL)\n            {\n                ATLTRACE(\"Unable to enable MMCSS on render thread: %d\\n\", GetLastError());\n            }\n            else\n            {\n                AVRT_FUNC_PTR(AvSetMmThreadPriority);\n                if (AvSetMmThreadPriorityPtr)\n                    ATLVERIFY(AvSetMmThreadPriorityPtr(m_mmcssHandle, AVRT_PRIORITY_CRITICAL));\n            }\n        }\n    }\n}\n\nvoid AudioPlayerWasapi::DeinitializeThread()\n{\n    if (m_mmcssHandle)\n    {\n        if (auto avrtHandle = GetAvrtHandle())\n        {\n            AVRT_FUNC_PTR(AvRevertMmThreadCharacteristics);\n            if (AvRevertMmThreadCharacteristicsPtr)\n            {\n                ATLVERIFY(AvRevertMmThreadCharacteristicsPtr(m_mmcssHandle));\n                m_mmcssHandle = NULL;\n            }\n        }\n    }\n\n    if (m_coUnitialize)\n    {\n        CoUninitialize();\n        m_coUnitialize = false;\n    }\n}\n\n#undef AVRT_FUNC_PTR\n\nvoid AudioPlayerWasapi::WaveOutReset()\n{\n    if (m_AudioClient)\n    {\n        m_AudioClient->Reset();\n    }\n}\n\nvoid AudioPlayerWasapi::Close()\n{\n    m_SimpleAudioVolume.Release();\n    m_RenderClient.Release();\n    m_AudioClient.Release();\n}\n\nvoid AudioPlayerWasapi::SetVolume(double volume)\n{\n    if (m_SimpleAudioVolume)\n    {\n        m_SimpleAudioVolume->SetMasterVolume((float)volume, NULL);\n    }\n}\n\ndouble AudioPlayerWasapi::GetVolume() const\n{\n    float result = 1.;\n    if (m_SimpleAudioVolume)\n    {\n        m_SimpleAudioVolume->GetMasterVolume(&result);\n    }\n    return result;\n}\n\nvoid AudioPlayerWasapi::WaveOutPause()\n{\n    if (m_AudioClient)\n    {\n        m_AudioClient->Stop();\n    }\n}\n\nvoid AudioPlayerWasapi::WaveOutRestart()\n{\n    if (m_AudioClient)\n    {\n        m_AudioClient->Start();\n    }\n}\n"
  },
  {
    "path": "audio/AudioPlayerWasapi.h",
    "content": "#pragma once\n\n#include \"../video/audioplayer.h\"\n\n#include <atlbase.h>\n\nstruct IAudioClient;\nstruct IAudioRenderClient;\nstruct ISimpleAudioVolume;\n\nclass AudioPlayerWasapi :\n    public IAudioPlayer\n{\npublic:\n    AudioPlayerWasapi();\n    ~AudioPlayerWasapi() override;\n\n    AudioPlayerWasapi(const AudioPlayerWasapi&) = delete;\n    AudioPlayerWasapi& operator=(const AudioPlayerWasapi&) = delete;\n\n    void SetCallback(IAudioPlayerCallback* callback) override\n    {\n        m_callback = callback;\n    }\n\n    void InitializeThread() override;\n    void DeinitializeThread() override;\n\n    void WaveOutReset() override;\n\n    void Close() override;\n    bool Open(int bytesPerSample, int channels, int* samplesPerSec) override;\n\n    void SetVolume(double volume) override;\n    double GetVolume() const override;\n\n    void WaveOutPause() override;\n    void WaveOutRestart() override;\n\n    bool WriteAudio(uint8_t* write_data, int64_t write_size) override;\n\nprivate:\n    IAudioPlayerCallback* m_callback;\n\n    HANDLE m_hAudioSamplesRenderEvent;\n\n    CComPtr<IAudioClient> m_AudioClient;\n    CComPtr<IAudioRenderClient> m_RenderClient;\n    CComPtr<ISimpleAudioVolume> m_SimpleAudioVolume;\n\n    unsigned int m_BufferSize;\n    unsigned int m_FrameSize;\n    unsigned int m_samplesPerSec;\n\n    HANDLE m_mmcssHandle;\n\n    bool m_coUnitialize;\n};\n"
  },
  {
    "path": "audio/ReadMe.txt",
    "content": "========================================================================\n    STATIC LIBRARY : audio Project Overview\n========================================================================\n\nAppWizard has created this audio library project for you.\n\nNo source files were created as part of your project.\n\n\naudio.vcxproj\n    This is the main project file for VC++ projects generated using an Application Wizard.\n    It contains information about the version of Visual C++ that generated the file, and\n    information about the platforms, configurations, and project features selected with the\n    Application Wizard.\n\naudio.vcxproj.filters\n    This is the filters file for VC++ projects generated using an Application Wizard. \n    It contains information about the association between the files in your project \n    and the filters. This association is used in the IDE to show grouping of files with\n    similar extensions under a specific node (for e.g. \".cpp\" files are associated with the\n    \"Source Files\" filter).\n\n/////////////////////////////////////////////////////////////////////////////\nOther notes:\n\nAppWizard uses \"TODO:\" comments to indicate parts of the source code you\nshould add to or customize.\n\n/////////////////////////////////////////////////////////////////////////////\n"
  },
  {
    "path": "audio/audio.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{8B955995-B5EC-41F0-940A-48A6F17BCBB8}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>audio</RootNamespace>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_USE_MATH_DEFINES;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalOptions>/std:c++latest /D_HAS_CXX17=1 %(AdditionalOptions)</AdditionalOptions>\n      <FloatingPointModel>Fast</FloatingPointModel>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_USE_MATH_DEFINES;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalOptions>/std:c++latest /D_HAS_CXX17=1 %(AdditionalOptions)</AdditionalOptions>\n      <FloatingPointModel>Fast</FloatingPointModel>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>_USE_MATH_DEFINES;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalOptions>/std:c++latest /D_HAS_CXX17=1 %(AdditionalOptions)</AdditionalOptions>\n      <FloatingPointModel>Fast</FloatingPointModel>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>_USE_MATH_DEFINES;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalOptions>/std:c++latest /D_HAS_CXX17=1 %(AdditionalOptions)</AdditionalOptions>\n      <FloatingPointModel>Fast</FloatingPointModel>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <Text Include=\"ReadMe.txt\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"AudioPitchDecorator.h\" />\n    <ClInclude Include=\"AudioPlayerImpl.h\" />\n    <ClInclude Include=\"AudioPlayerWasapi.h\" />\n    <ClInclude Include=\"smbPitchShift.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"AudioPitchDecorator.cpp\" />\n    <ClCompile Include=\"AudioPlayerImpl.cpp\" />\n    <ClCompile Include=\"AudioPlayerWasapi.cpp\" />\n    <ClCompile Include=\"smbPitchShift.cpp\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "audio/audio.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <Text Include=\"ReadMe.txt\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"AudioPitchDecorator.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AudioPlayerImpl.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AudioPlayerWasapi.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"smbPitchShift.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"AudioPitchDecorator.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"AudioPlayerImpl.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"AudioPlayerWasapi.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"smbPitchShift.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "audio/smbPitchShift.cpp",
    "content": "/****************************************************************************\n*\n* NAME: smbPitchShift.cpp\n* VERSION: 1.2\n* HOME URL: http://blogs.zynaptiq.com/bernsee\n* KNOWN BUGS: none\n*\n* SYNOPSIS: Routine for doing pitch shifting while maintaining\n* duration using the Short Time Fourier Transform.\n*\n* DESCRIPTION: The routine takes a pitchShift factor value which is between 0.5\n* (one octave down) and 2. (one octave up). A value of exactly 1 does not change\n* the pitch. numSampsToProcess tells the routine how many samples in indata[0...\n* numSampsToProcess-1] should be pitch shifted and moved to outdata[0 ...\n* numSampsToProcess-1]. The two buffers can be identical (ie. it can process the\n* data in-place). fftFrameSize defines the FFT frame size used for the\n* processing. Typical values are 1024, 2048 and 4096. It may be any value <=\n* MAX_FRAME_LENGTH but it MUST be a power of 2. osamp is the STFT\n* oversampling factor which also determines the overlap between adjacent STFT\n* frames. It should at least be 4 for moderate scaling ratios. A value of 32 is\n* recommended for best quality. sampleRate takes the sample rate for the signal \n* in unit Hz, ie. 44100 for 44.1 kHz audio. The data passed to the routine in \n* indata[] should be in the range [-1.0, 1.0), which is also the output range \n* for the data, make sure you scale the data accordingly (for 16bit signed integers\n* you would have to divide (and multiply) by 32768). \n*\n* COPYRIGHT 1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>\n*\n* \t\t\t\t\t\tThe Wide Open License (WOL)\n*\n* Permission to use, copy, modify, distribute and sell this software and its\n* documentation for any purpose is hereby granted without fee, provided that\n* the above copyright notice and this license appear in all source copies. \n* THIS SOFTWARE IS PROVIDED \"AS IS\" WITHOUT EXPRESS OR IMPLIED WARRANTY OF\n* ANY KIND. See http://www.dspguru.com/wol.htm for more information.\n*\n*****************************************************************************/ \n\n#include \"smbPitchShift.h\"\n\n#include <string.h>\n#include <math.h>\n#include <stdio.h>\n\n#include <memory>\n\n#include <emmintrin.h>\n#include <pmmintrin.h>\n#include <xmmintrin.h>\n\n\nnamespace {\n\nvoid smbFft(float *fftBuffer, long fftFrameSize, long sign)\n/* \n    FFT routine, (C)1996 S.M.Bernsee. Sign = -1 is FFT, 1 is iFFT (inverse)\n    Fills fftBuffer[0...2*fftFrameSize-1] with the Fourier transform of the\n    time domain data in fftBuffer[0...2*fftFrameSize-1]. The FFT array takes\n    and returns the cosine and sine parts in an interleaved manner, ie.\n    fftBuffer[0] = cosPart[0], fftBuffer[1] = sinPart[0], asf. fftFrameSize\n    must be a power of 2. It expects a complex input signal (see footnote 2),\n    ie. when working with 'common' audio signals our input signal has to be\n    passed as {in[0],0.,in[1],0.,in[2],0.,...} asf. In that case, the transform\n    of the frequencies of interest is in fftBuffer[0...fftFrameSize].\n*/\n{\n    const auto number = 2 * fftFrameSize - 2;\n    for (long i = 2, j = 0; i < number; i += 2) {\n        for (long bitm = fftFrameSize; bitm != 1; bitm >>= 1)\n        {\n            if (j & bitm)\n                j &= ~bitm;\n            else\n            {\n                j |= bitm;\n                break;\n            }\n        }\n        if (i < j) {\n            auto p1 = fftBuffer+i; \n            auto p2 = fftBuffer+j;\n            auto temp = *p1; *(p1++) = *p2;\n            *(p2++) = temp; temp = *p1;\n            *p1 = *p2; *p2 = temp;\n        }\n    }\n    for (long k = 0, le = 2; k < (long)(log(fftFrameSize)/log(2.)+.5); k++) {\n        le <<= 1;\n        const auto le2 = le>>1;\n        __declspec(align(8)) struct { float r, i; } u{ 1.0, 0.0 };\n\n        const float arg = M_PI / (le2>>1);\n        const float wr = cos(arg);\n        const float wi = sign*sin(arg);\n        for (long j = 0; j < le2; j += 2) {\n            auto p1r = fftBuffer+j; \n            auto p2r = p1r+le2;\n\n            __m128 u_ = _mm_castpd_ps(_mm_movedup_pd(_mm_load_sd((const double*)&u)));\n\n            __m128 ldup = _mm_moveldup_ps(u_);\n            __m128 hdup = _mm_movehdup_ps(u_);\n\n            long i = j;\n            for (; i < 2*fftFrameSize - le; i += le * 2) \n            {\n                __m128 p2 = _mm_loadh_pi(_mm_castpd_ps(_mm_load_sd((const double*)p2r)), (const __m64*)(p2r + le));\n                __m128 part1 = _mm_mul_ps(p2, ldup);\n                __m128 part2 = _mm_mul_ps(p2, hdup);\n                part2 = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(part2), _MM_SHUFFLE(2, 3, 0, 1)));\n                __m128 t = _mm_addsub_ps(part1, part2);\n\n                __m128 p1 = _mm_loadh_pi(_mm_castpd_ps(_mm_load_sd((const double*)p1r)), (const __m64*)(p1r + le));\n                __m128 buffer = _mm_sub_ps(p1, t);\n\n                _mm_storeh_pi((__m64*)(p2r + le), buffer);\n                _mm_storel_pi((__m64*)p2r, buffer);\n\n                buffer = _mm_add_ps(p1, t);\n                _mm_storeh_pi((__m64*)(p1r + le), buffer);\n                _mm_storel_pi((__m64*)p1r, buffer);\n\n                p1r += le * 2; \n                p2r += le * 2; \n            }\n\n\n            if (i < 2 * fftFrameSize) {\n                const auto p1i = p1r + 1;\n                const auto p2i = p2r + 1;\n                const float tr = *p2r * u.r - *p2i * u.i;\n                const float ti = *p2r * u.i + *p2i * u.r;\n                *p2r = *p1r - tr; *p2i = *p1i - ti;\n                *p1r += tr; *p1i += ti;\n            }\n\n\n            const float tr = u.r*wr - u.i*wi;\n            u.i = u.r*wi + u.i*wr;\n            u.r = tr;\n        }\n    }\n}\n\n\n// -----------------------------------------------------------------------------------------------------------------\n\n/*\n\n    12/12/02, smb\n    \n    PLEASE NOTE:\n    \n    There have been some reports on domain errors when the atan2() function was used\n    as in the above code. Usually, a domain error should not interrupt the program flow\n    (maybe except in Debug mode) but rather be handled \"silently\" and a global variable\n    should be set according to this error. However, on some occasions people ran into\n    this kind of scenario, so a replacement atan2() function is provided here.\n    \n    If you are experiencing domain errors and your program stops, simply replace all\n    instances of atan2() with calls to the smbAtan2() function below.\n    \n*/\n\n// Approximation was taken from:\n// http://www-labs.iro.umontreal.ca/~mignotte/IFT2425/Documents/EfficientApproximationArctgFunction.pdf\n//\n// |Error = fast_atan2(y, x) - atan2f(y, x)| < 0.00468 rad\n//\n// Octants:\n//         pi/2\n//       ` 3 | 2 /\n//        `  |  /\n//       4 ` | / 1\n//   pi -----+----- 0\n//       5 / | ` 8\n//        /  |  `\n//       / 6 | 7 `\n//         3pi/2\n\ntemplate<typename T> T CopySign(T v, T x)\n{\n    return (x >= 0) ? v : -v;\n}\n\ndouble smbAtan2(double y, double x)\n{\n    constexpr double scaling_constant = 0.28086;\n\n    if (x == 0.) {\n        // Special case atan2(0.0, 0.0) = 0.0\n        if (y == 0.) {\n            return 0.;\n        }\n\n        // x is zero so we are either at pi/2 for (y > 0) or -pi/2 for (y < 0)\n        return CopySign(M_PI_2, y);\n    }\n\n    // Calculate quotient of y and x\n    const auto div = y / x;\n\n    // Determine in which octants we can be, if |y| is smaller than |x| (|div|<1)\n    // then we are either in 1,4,5 or 8 else we are in 2,3,6 or 7.\n    if (fabs(div) < 1.) {\n        // We are in 1,4,5 or 8\n\n        const auto atan = div / (1. + scaling_constant * div * div);\n\n        // If we are in 4 or 5 we need to add pi or -pi respectively\n        if (x < 0.) {\n            return CopySign(M_PI, y) + atan;\n        }\n        return atan;\n    }\n\n    // We are in 2,3,6 or 7\n    return CopySign(M_PI_2, y) - div / (div * div + scaling_constant);\n}\n\n//double smbAtan2(double x, double y)\n//{\n//  double signx;\n//  if (x > 0.) signx = 1.;  \n//  else signx = -1.;\n//  \n//  if (x == 0.) return 0.;\n//  if (y == 0.) return signx * M_PI / 2.;\n//  \n//  return atan2(x, y);\n//}\n\n\n} // namespace\n\n\n// -----------------------------------------------------------------------------------------------------------------\n\n\nvoid CSmbPitchShift::smbPitchShift(float pitchShift, long numSampsToProcess, long fftFrameSize, long osamp, float sampleRate, float *indata, float *outdata)\n/*\n    Routine smbPitchShift(). See top of file for explanation\n    Purpose: doing pitch shifting while maintaining duration using the Short\n    Time Fourier Transform.\n    Author: (c)1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>\n*/\n{\n    /* set up some handy variables */\n    const long fftFrameSize2 = fftFrameSize/2;\n    const long stepSize = fftFrameSize/osamp;\n    const double freqPerBin = sampleRate/(double)fftFrameSize;\n    const double expct = 2.*M_PI*(double)stepSize/(double)fftFrameSize;\n    const long inFifoLatency = fftFrameSize-stepSize;\n    if (!gRover) \n        gRover = inFifoLatency;\n\n    /* initialize our static arrays */\n    if (!gInit) {\n        memset(gInFIFO, 0, MAX_FRAME_LENGTH*sizeof(float));\n        memset(gOutFIFO, 0, MAX_FRAME_LENGTH*sizeof(float));\n        memset(gFFTworksp, 0, 2*MAX_FRAME_LENGTH*sizeof(float));\n        memset(gLastPhase, 0, (MAX_FRAME_LENGTH/2+1)*sizeof(float));\n        memset(gSumPhase, 0, (MAX_FRAME_LENGTH/2+1)*sizeof(float));\n        memset(gOutputAccum, 0, 2*MAX_FRAME_LENGTH*sizeof(float));\n        memset(gAnaFreq, 0, MAX_FRAME_LENGTH*sizeof(float));\n        memset(gAnaMagn, 0, MAX_FRAME_LENGTH*sizeof(float));\n\n        memset(gErrors, 0, MAX_FRAME_LENGTH * sizeof(float));\n\n        gInit = true;\n    }\n\n    auto window = std::make_unique<double[]>(fftFrameSize);\n    for (long k = 0; k < fftFrameSize; k++) {\n        window[k] = -.5*cos(2.*M_PI*(double)k / (double)fftFrameSize) + .5;\n    }\n\n    /* main processing loop */\n    for (long i = 0; i < numSampsToProcess; i++){\n\n        /* As long as we have not yet collected enough data just read in */\n        gInFIFO[gRover] = indata[i];\n        outdata[i] = gOutFIFO[gRover-inFifoLatency];\n        gRover++;\n\n        /* now we have enough data for processing */\n        if (gRover >= fftFrameSize) {\n            gRover = inFifoLatency;\n\n            /* do windowing and re,im interleave */\n            for (long k = 0; k < fftFrameSize;k++) {\n                gFFTworksp[2*k] = gInFIFO[k] * window[k];\n                gFFTworksp[2*k+1] = 0.;\n            }\n\n\n            /* ***************** ANALYSIS ******************* */\n            /* do transform */\n            smbFft(gFFTworksp, fftFrameSize, -1);\n\n            /* this is the analysis step */\n            for (long k = 0; k <= fftFrameSize2; k++) {\n\n                /* de-interlace FFT buffer */\n                const auto real = gFFTworksp[2*k];\n                const auto imag = gFFTworksp[2*k+1];\n\n                /* compute magnitude and phase */\n                const auto magn = 2.*hypotf(real, imag);\n                const auto phase = smbAtan2(imag,real);\n\n                /* compute phase difference */\n                double tmp = phase - gLastPhase[k];\n                gLastPhase[k] = phase;\n\n                /* subtract expected phase difference */\n                tmp -= (double)k*expct;\n\n                /* map delta phase into +/- Pi interval */\n                /* get deviation from bin frequency from the +/- Pi interval */\n                tmp /= (2.*M_PI);\n                tmp = osamp * (tmp - floor(tmp + 0.5)); // faster than round\n\n                /* compute the k-th partials' true frequency */\n                tmp = (k + tmp) * freqPerBin;\n\n                /* store magnitude and true frequency in analysis arrays */\n                gAnaMagn[k] = magn;\n                gAnaFreq[k] = tmp;\n\n            }\n\n            /* ***************** PROCESSING ******************* */\n            /* this does the actual pitch shifting */\n            memset(gSynMagn, 0, fftFrameSize*sizeof(float));\n            memset(gSynFreq, 0, fftFrameSize*sizeof(float));\n            for (long k = 0; k <= fftFrameSize2; k++) {\n\n                //const long index = k*pitchShift;\n                const auto originalIndex = k*pitchShift + gErrors[k];\n                const long index = originalIndex;\n                gErrors[k] = originalIndex - index;\n\n                if (index <= fftFrameSize2) {\n                    const bool useSynFreq = gSynMagn[index] < gAnaMagn[k];\n\n                    gSynMagn[index] += gAnaMagn[k];\n                    if (useSynFreq) {\n                        gSynFreq[index] = gAnaFreq[k] * pitchShift;\n                    }\n                } \n            }\n            \n            /* ***************** SYNTHESIS ******************* */\n            /* this is the synthesis step */\n            for (long k = 0; k <= fftFrameSize2; k++) {\n\n                /* get magnitude and true frequency from synthesis arrays */\n                const auto magn = gSynMagn[k];\n                double tmp = gSynFreq[k];\n\n                /* get bin deviation from freq deviation */\n                tmp /= freqPerBin;\n\n                /* subtract bin mid frequency */\n                tmp -= k;\n\n                /* take osamp into account */\n                tmp = 2.*M_PI*tmp/osamp;\n\n                /* add the overlap phase advance back in */\n                tmp += (double)k*expct;\n\n                /* accumulate delta phase to get bin phase */\n                gSumPhase[k] += tmp;\n                const auto phase = gSumPhase[k];\n\n                /* get real and imag part and re-interleave */\n                gFFTworksp[2*k] = magn*cosf(phase);\n                gFFTworksp[2*k+1] = magn*sinf(phase);\n            } \n\n            /* zero negative frequencies */\n            for (long k = fftFrameSize+2; k < 2*fftFrameSize; k++) gFFTworksp[k] = 0.;\n\n            /* do inverse transform */\n            smbFft(gFFTworksp, fftFrameSize, 1);\n\n            /* do windowing and add to output accumulator */ \n            for(long k=0; k < fftFrameSize; k++) {\n                gOutputAccum[k] += 2. * window[k] * gFFTworksp[2*k]/(fftFrameSize2*osamp);\n            }\n            for (long k = 0; k < stepSize; k++) gOutFIFO[k] = gOutputAccum[k];\n\n            /* shift accumulator */\n            memmove(gOutputAccum, gOutputAccum+stepSize, fftFrameSize*sizeof(float));\n\n            /* move input FIFO */\n            for (long k = 0; k < inFifoLatency; k++) gInFIFO[k] = gInFIFO[k+stepSize];\n        }\n    }\n}\n"
  },
  {
    "path": "audio/smbPitchShift.h",
    "content": "#pragma once\n\n// http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/\n\nclass CSmbPitchShift\n{\n    enum { MAX_FRAME_LENGTH = 8192 };\n\npublic:\n    void reset()\n    {\n        gRover = 0;\n        gInit = false;\n    }\n    void smbPitchShift(float pitchShift, long numSampsToProcess, long fftFrameSize, long osamp, float sampleRate, float *indata, float *outdata);\n\nprivate:\n    float gInFIFO[MAX_FRAME_LENGTH];\n    float gOutFIFO[MAX_FRAME_LENGTH];\n    float gFFTworksp[2 * MAX_FRAME_LENGTH];\n    float gLastPhase[MAX_FRAME_LENGTH / 2 + 1];\n    float gSumPhase[MAX_FRAME_LENGTH / 2 + 1];\n    float gOutputAccum[2 * MAX_FRAME_LENGTH];\n    float gAnaFreq[MAX_FRAME_LENGTH];\n    float gAnaMagn[MAX_FRAME_LENGTH];\n    float gSynFreq[MAX_FRAME_LENGTH];\n    float gSynMagn[MAX_FRAME_LENGTH];\n\n    float gErrors[MAX_FRAME_LENGTH];\n\n    long gRover = 0;\n    bool gInit = false;\n};"
  },
  {
    "path": "core/ac_export.h",
    "content": "\n#ifndef AC_EXPORT_H\n#define AC_EXPORT_H\n\n#ifdef AC_STATIC_DEFINE\n#  define AC_EXPORT\n#  define AC_NO_EXPORT\n#else\n#  ifndef AC_EXPORT\n#    ifdef Anime4KCPPCore_EXPORTS\n        /* We are building this library */\n#      define AC_EXPORT \n#    else\n        /* We are using this library */\n#      define AC_EXPORT \n#    endif\n#  endif\n\n#  ifndef AC_NO_EXPORT\n#    define AC_NO_EXPORT \n#  endif\n#endif\n\n#ifndef AC_DEPRECATED\n#  define AC_DEPRECATED __declspec(deprecated)\n#endif\n\n#ifndef AC_DEPRECATED_EXPORT\n#  define AC_DEPRECATED_EXPORT AC_EXPORT AC_DEPRECATED\n#endif\n\n#ifndef AC_DEPRECATED_NO_EXPORT\n#  define AC_DEPRECATED_NO_EXPORT AC_NO_EXPORT AC_DEPRECATED\n#endif\n\n#if 0 /* DEFINE_NO_DEPRECATED */\n#  ifndef AC_NO_DEPRECATED\n#    define AC_NO_DEPRECATED\n#  endif\n#endif\n\n#endif /* AC_EXPORT_H */\n"
  },
  {
    "path": "edit_git_subst_cfg.cmd",
    "content": "notepad.exe \"%LOCALAPPDATA%\\git-subst.cfg\"\n"
  },
  {
    "path": "ffmpeg-3.3.3-experimental-patch/common.before.h",
    "content": "/*\n * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/**\n * @file\n * common internal and external API header\n */\n\n#ifndef AVUTIL_COMMON_H\n#define AVUTIL_COMMON_H\n\n#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) && !defined(UINT64_C)\n#error missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS\n#endif\n\n#include <errno.h>\n#include <inttypes.h>\n#include <limits.h>\n#include <math.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"attributes.h\"\n#include \"macros.h\"\n#include \"version.h\"\n#include \"libavutil/avconfig.h\"\n\n#if AV_HAVE_BIGENDIAN\n#   define AV_NE(be, le) (be)\n#else\n#   define AV_NE(be, le) (le)\n#endif\n\n//rounded division & shift\n#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b))\n/* assume b>0 */\n#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))\n/* Fast a/(1<<b) rounded toward +inf. Assume a>=0 and b>=0 */\n#define AV_CEIL_RSHIFT(a,b) (!av_builtin_constant_p(b) ? -((-(a)) >> (b)) \\\n                                                       : ((a) + (1<<(b)) - 1) >> (b))\n/* Backwards compat. */\n#define FF_CEIL_RSHIFT AV_CEIL_RSHIFT\n\n#define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b))\n#define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b))\n\n/**\n * Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they\n * are not representable as absolute values of their type. This is the same\n * as with *abs()\n * @see FFNABS()\n */\n#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))\n#define FFSIGN(a) ((a) > 0 ? 1 : -1)\n\n/**\n * Negative Absolute value.\n * this works for all integers of all types.\n * As with many macros, this evaluates its argument twice, it thus must not have\n * a sideeffect, that is FFNABS(x++) has undefined behavior.\n */\n#define FFNABS(a) ((a) <= 0 ? (a) : (-(a)))\n\n/**\n * Comparator.\n * For two numerical expressions x and y, gives 1 if x > y, -1 if x < y, and 0\n * if x == y. This is useful for instance in a qsort comparator callback.\n * Furthermore, compilers are able to optimize this to branchless code, and\n * there is no risk of overflow with signed types.\n * As with many macros, this evaluates its argument multiple times, it thus\n * must not have a side-effect.\n */\n#define FFDIFFSIGN(x,y) (((x)>(y)) - ((x)<(y)))\n\n#define FFMAX(a,b) ((a) > (b) ? (a) : (b))\n#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c)\n#define FFMIN(a,b) ((a) > (b) ? (b) : (a))\n#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c)\n\n#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)\n#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))\n\n/* misc math functions */\n\n#ifdef HAVE_AV_CONFIG_H\n#   include \"config.h\"\n#   include \"intmath.h\"\n#endif\n\n/* Pull in unguarded fallback defines at the end of this file. */\n#include \"common.h\"\n\n#ifndef av_log2\nav_const int av_log2(unsigned v);\n#endif\n\n#ifndef av_log2_16bit\nav_const int av_log2_16bit(unsigned v);\n#endif\n\n/**\n * Clip a signed integer value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const int av_clip_c(int a, int amin, int amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/**\n * Clip a signed 64bit integer value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/**\n * Clip a signed integer value into the 0-255 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const uint8_t av_clip_uint8_c(int a)\n{\n    if (a&(~0xFF)) return (-a)>>31;\n    else           return a;\n}\n\n/**\n * Clip a signed integer value into the -128,127 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const int8_t av_clip_int8_c(int a)\n{\n    if ((a+0x80U) & ~0xFF) return (a>>31) ^ 0x7F;\n    else                  return a;\n}\n\n/**\n * Clip a signed integer value into the 0-65535 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const uint16_t av_clip_uint16_c(int a)\n{\n    if (a&(~0xFFFF)) return (-a)>>31;\n    else             return a;\n}\n\n/**\n * Clip a signed integer value into the -32768,32767 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const int16_t av_clip_int16_c(int a)\n{\n    if ((a+0x8000U) & ~0xFFFF) return (a>>31) ^ 0x7FFF;\n    else                      return a;\n}\n\n/**\n * Clip a signed 64-bit integer value into the -2147483648,2147483647 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const int32_t av_clipl_int32_c(int64_t a)\n{\n    if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF);\n    else                                         return (int32_t)a;\n}\n\n/**\n * Clip a signed integer into the -(2^p),(2^p-1) range.\n * @param  a value to clip\n * @param  p bit position to clip at\n * @return clipped value\n */\nstatic av_always_inline av_const int av_clip_intp2_c(int a, int p)\n{\n    if (((unsigned)a + (1 << p)) & ~((2 << p) - 1))\n        return (a >> 31) ^ ((1 << p) - 1);\n    else\n        return a;\n}\n\n/**\n * Clip a signed integer to an unsigned power of two range.\n * @param  a value to clip\n * @param  p bit position to clip at\n * @return clipped value\n */\nstatic av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p)\n{\n    if (a & ~((1<<p) - 1)) return -a >> 31 & ((1<<p) - 1);\n    else                   return  a;\n}\n\n/**\n * Clear high bits from an unsigned integer starting with specific bit position\n * @param  a value to clip\n * @param  p bit position to clip at\n * @return clipped value\n */\nstatic av_always_inline av_const unsigned av_mod_uintp2_c(unsigned a, unsigned p)\n{\n    return a & ((1 << p) - 1);\n}\n\n/**\n * Add two signed 32-bit values with saturation.\n *\n * @param  a one value\n * @param  b another value\n * @return sum with signed saturation\n */\nstatic av_always_inline int av_sat_add32_c(int a, int b)\n{\n    return av_clipl_int32((int64_t)a + b);\n}\n\n/**\n * Add a doubled value to another value with saturation at both stages.\n *\n * @param  a first value\n * @param  b value doubled and added to a\n * @return sum with signed saturation\n */\nstatic av_always_inline int av_sat_dadd32_c(int a, int b)\n{\n    return av_sat_add32(a, av_sat_add32(b, b));\n}\n\n/**\n * Clip a float value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const float av_clipf_c(float a, float amin, float amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/**\n * Clip a double value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const double av_clipd_c(double a, double amin, double amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/** Compute ceil(log2(x)).\n * @param x value used to compute ceil(log2(x))\n * @return computed ceiling of log2(x)\n */\nstatic av_always_inline av_const int av_ceil_log2_c(int x)\n{\n    return av_log2((x - 1) << 1);\n}\n\n/**\n * Count number of bits set to one in x\n * @param x value to count bits of\n * @return the number of bits set to one in x\n */\nstatic av_always_inline av_const int av_popcount_c(uint32_t x)\n{\n    x -= (x >> 1) & 0x55555555;\n    x = (x & 0x33333333) + ((x >> 2) & 0x33333333);\n    x = (x + (x >> 4)) & 0x0F0F0F0F;\n    x += x >> 8;\n    return (x + (x >> 16)) & 0x3F;\n}\n\n/**\n * Count number of bits set to one in x\n * @param x value to count bits of\n * @return the number of bits set to one in x\n */\nstatic av_always_inline av_const int av_popcount64_c(uint64_t x)\n{\n    return av_popcount((uint32_t)x) + av_popcount((uint32_t)(x >> 32));\n}\n\nstatic av_always_inline av_const int av_parity_c(uint32_t v)\n{\n    return av_popcount(v) & 1;\n}\n\n#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))\n#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24))\n\n/**\n * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form.\n *\n * @param val      Output value, must be an lvalue of type uint32_t.\n * @param GET_BYTE Expression reading one byte from the input.\n *                 Evaluated up to 7 times (4 for the currently\n *                 assigned Unicode range).  With a memory buffer\n *                 input, this could be *ptr++.\n * @param ERROR    Expression to be evaluated on invalid input,\n *                 typically a goto statement.\n *\n * @warning ERROR should not contain a loop control statement which\n * could interact with the internal while loop, and should force an\n * exit from the macro code (e.g. through a goto or a return) in order\n * to prevent undefined results.\n */\n#define GET_UTF8(val, GET_BYTE, ERROR)\\\n    val= (GET_BYTE);\\\n    {\\\n        uint32_t top = (val & 128) >> 1;\\\n        if ((val & 0xc0) == 0x80 || val >= 0xFE)\\\n            ERROR\\\n        while (val & top) {\\\n            int tmp= (GET_BYTE) - 128;\\\n            if(tmp>>6)\\\n                ERROR\\\n            val= (val<<6) + tmp;\\\n            top <<= 5;\\\n        }\\\n        val &= (top << 1) - 1;\\\n    }\n\n/**\n * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form.\n *\n * @param val       Output value, must be an lvalue of type uint32_t.\n * @param GET_16BIT Expression returning two bytes of UTF-16 data converted\n *                  to native byte order.  Evaluated one or two times.\n * @param ERROR     Expression to be evaluated on invalid input,\n *                  typically a goto statement.\n */\n#define GET_UTF16(val, GET_16BIT, ERROR)\\\n    val = GET_16BIT;\\\n    {\\\n        unsigned int hi = val - 0xD800;\\\n        if (hi < 0x800) {\\\n            val = GET_16BIT - 0xDC00;\\\n            if (val > 0x3FFU || hi > 0x3FFU)\\\n                ERROR\\\n            val += (hi<<10) + 0x10000;\\\n        }\\\n    }\\\n\n/**\n * @def PUT_UTF8(val, tmp, PUT_BYTE)\n * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long).\n * @param val is an input-only argument and should be of type uint32_t. It holds\n * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If\n * val is given as a function it is executed only once.\n * @param tmp is a temporary variable and should be of type uint8_t. It\n * represents an intermediate value during conversion that is to be\n * output by PUT_BYTE.\n * @param PUT_BYTE writes the converted UTF-8 bytes to any proper destination.\n * It could be a function or a statement, and uses tmp as the input byte.\n * For example, PUT_BYTE could be \"*output++ = tmp;\" PUT_BYTE will be\n * executed up to 4 times for values in the valid UTF-8 range and up to\n * 7 times in the general case, depending on the length of the converted\n * Unicode character.\n */\n#define PUT_UTF8(val, tmp, PUT_BYTE)\\\n    {\\\n        int bytes, shift;\\\n        uint32_t in = val;\\\n        if (in < 0x80) {\\\n            tmp = in;\\\n            PUT_BYTE\\\n        } else {\\\n            bytes = (av_log2(in) + 4) / 5;\\\n            shift = (bytes - 1) * 6;\\\n            tmp = (256 - (256 >> bytes)) | (in >> shift);\\\n            PUT_BYTE\\\n            while (shift >= 6) {\\\n                shift -= 6;\\\n                tmp = 0x80 | ((in >> shift) & 0x3f);\\\n                PUT_BYTE\\\n            }\\\n        }\\\n    }\n\n/**\n * @def PUT_UTF16(val, tmp, PUT_16BIT)\n * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes).\n * @param val is an input-only argument and should be of type uint32_t. It holds\n * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If\n * val is given as a function it is executed only once.\n * @param tmp is a temporary variable and should be of type uint16_t. It\n * represents an intermediate value during conversion that is to be\n * output by PUT_16BIT.\n * @param PUT_16BIT writes the converted UTF-16 data to any proper destination\n * in desired endianness. It could be a function or a statement, and uses tmp\n * as the input byte.  For example, PUT_BYTE could be \"*output++ = tmp;\"\n * PUT_BYTE will be executed 1 or 2 times depending on input character.\n */\n#define PUT_UTF16(val, tmp, PUT_16BIT)\\\n    {\\\n        uint32_t in = val;\\\n        if (in < 0x10000) {\\\n            tmp = in;\\\n            PUT_16BIT\\\n        } else {\\\n            tmp = 0xD800 | ((in - 0x10000) >> 10);\\\n            PUT_16BIT\\\n            tmp = 0xDC00 | ((in - 0x10000) & 0x3FF);\\\n            PUT_16BIT\\\n        }\\\n    }\\\n\n\n\n#include \"mem.h\"\n\n#ifdef HAVE_AV_CONFIG_H\n#    include \"internal.h\"\n#endif /* HAVE_AV_CONFIG_H */\n\n#endif /* AVUTIL_COMMON_H */\n\n/*\n * The following definitions are outside the multiple inclusion guard\n * to ensure they are immediately available in intmath.h.\n */\n\n#ifndef av_ceil_log2\n#   define av_ceil_log2     av_ceil_log2_c\n#endif\n#ifndef av_clip\n#   define av_clip          av_clip_c\n#endif\n#ifndef av_clip64\n#   define av_clip64        av_clip64_c\n#endif\n#ifndef av_clip_uint8\n#   define av_clip_uint8    av_clip_uint8_c\n#endif\n#ifndef av_clip_int8\n#   define av_clip_int8     av_clip_int8_c\n#endif\n#ifndef av_clip_uint16\n#   define av_clip_uint16   av_clip_uint16_c\n#endif\n#ifndef av_clip_int16\n#   define av_clip_int16    av_clip_int16_c\n#endif\n#ifndef av_clipl_int32\n#   define av_clipl_int32   av_clipl_int32_c\n#endif\n#ifndef av_clip_intp2\n#   define av_clip_intp2    av_clip_intp2_c\n#endif\n#ifndef av_clip_uintp2\n#   define av_clip_uintp2   av_clip_uintp2_c\n#endif\n#ifndef av_mod_uintp2\n#   define av_mod_uintp2    av_mod_uintp2_c\n#endif\n#ifndef av_sat_add32\n#   define av_sat_add32     av_sat_add32_c\n#endif\n#ifndef av_sat_dadd32\n#   define av_sat_dadd32    av_sat_dadd32_c\n#endif\n#ifndef av_clipf\n#   define av_clipf         av_clipf_c\n#endif\n#ifndef av_clipd\n#   define av_clipd         av_clipd_c\n#endif\n#ifndef av_popcount\n#   define av_popcount      av_popcount_c\n#endif\n#ifndef av_popcount64\n#   define av_popcount64    av_popcount64_c\n#endif\n#ifndef av_parity\n#   define av_parity        av_parity_c\n#endif\n"
  },
  {
    "path": "ffmpeg-3.3.3-experimental-patch/common.h",
    "content": "/*\n * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/**\n * @file\n * common internal and external API header\n */\n\n#ifndef AVUTIL_COMMON_H\n#define AVUTIL_COMMON_H\n\n#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) && !defined(UINT64_C)\n#error missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS\n#endif\n\n#include <errno.h>\n#include <inttypes.h>\n#include <limits.h>\n#include <math.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"attributes.h\"\n#include \"macros.h\"\n#include \"version.h\"\n#include \"libavutil/avconfig.h\"\n\n#if AV_HAVE_BIGENDIAN\n#   define AV_NE(be, le) (be)\n#else\n#   define AV_NE(be, le) (le)\n#endif\n\n//rounded division & shift\n#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b))\n/* assume b>0 */\n#define ROUNDED_DIV(a,b) (((a)>0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))\n/* Fast a/(1<<b) rounded toward +inf. Assume a>=0 and b>=0 */\n#define AV_CEIL_RSHIFT(a,b) (!av_builtin_constant_p(b) ? -((-(a)) >> (b)) \\\n                                                       : ((a) + (1<<(b)) - 1) >> (b))\n/* Backwards compat. */\n#define FF_CEIL_RSHIFT AV_CEIL_RSHIFT\n\n#define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b))\n#define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b))\n\n/**\n * Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they\n * are not representable as absolute values of their type. This is the same\n * as with *abs()\n * @see FFNABS()\n */\n#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))\n#define FFSIGN(a) ((a) > 0 ? 1 : -1)\n\n/**\n * Negative Absolute value.\n * this works for all integers of all types.\n * As with many macros, this evaluates its argument twice, it thus must not have\n * a sideeffect, that is FFNABS(x++) has undefined behavior.\n */\n#define FFNABS(a) ((a) <= 0 ? (a) : (-(a)))\n\n/**\n * Comparator.\n * For two numerical expressions x and y, gives 1 if x > y, -1 if x < y, and 0\n * if x == y. This is useful for instance in a qsort comparator callback.\n * Furthermore, compilers are able to optimize this to branchless code, and\n * there is no risk of overflow with signed types.\n * As with many macros, this evaluates its argument multiple times, it thus\n * must not have a side-effect.\n */\n#define FFDIFFSIGN(x,y) (((x)>(y)) - ((x)<(y)))\n\n#define FFMAX(a,b) ((a) > (b) ? (a) : (b))\n#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c)\n#define FFMIN(a,b) ((a) > (b) ? (b) : (a))\n#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c)\n\n#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)\n#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))\n\n/* misc math functions */\n\n#ifdef HAVE_AV_CONFIG_H\n#   include \"config.h\"\n#   include \"intmath.h\"\n#endif\n\n/* Pull in unguarded fallback defines at the end of this file. */\n#include \"common.h\"\n\n#ifndef av_log2\nav_const int av_log2(unsigned v);\n#endif\n\n#ifndef av_log2_16bit\nav_const int av_log2_16bit(unsigned v);\n#endif\n\n/**\n * Clip a signed integer value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const int av_clip_c(int a, int amin, int amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/**\n * Clip a signed 64bit integer value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/**\n * Clip a signed integer value into the 0-255 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const uint8_t av_clip_uint8_c(int a)\n{\n    if (a&(~0xFF)) return (-a)>>31;\n    else           return a;\n}\n\n/**\n * Clip a signed integer value into the -128,127 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const int8_t av_clip_int8_c(int a)\n{\n    if ((a+0x80U) & ~0xFF) return (a>>31) ^ 0x7F;\n    else                  return a;\n}\n\n/**\n * Clip a signed integer value into the 0-65535 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const uint16_t av_clip_uint16_c(int a)\n{\n    if (a&(~0xFFFF)) return (-a)>>31;\n    else             return a;\n}\n\n/**\n * Clip a signed integer value into the -32768,32767 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const int16_t av_clip_int16_c(int a)\n{\n    const int16_t noOverflowCandidate = a;\n    return (noOverflowCandidate == a) ? noOverflowCandidate : ((noOverflowCandidate < a) ? INT16_MAX : INT16_MIN);\n}\n\n/**\n * Clip a signed 64-bit integer value into the -2147483648,2147483647 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const int32_t av_clipl_int32_c(int64_t a)\n{\n    if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF);\n    else                                         return (int32_t)a;\n}\n\n/**\n * Clip a signed integer into the -(2^p),(2^p-1) range.\n * @param  a value to clip\n * @param  p bit position to clip at\n * @return clipped value\n */\nstatic av_always_inline av_const int av_clip_intp2_c(int a, int p)\n{\n    if (((unsigned)a + (1 << p)) & ~((2 << p) - 1))\n        return (a >> 31) ^ ((1 << p) - 1);\n    else\n        return a;\n}\n\n/**\n * Clip a signed integer to an unsigned power of two range.\n * @param  a value to clip\n * @param  p bit position to clip at\n * @return clipped value\n */\nstatic av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p)\n{\n    const unsigned int bits = ((1 << p) - 1);\n    return (((unsigned int)a) <= bits) ? a : ((a < 0) ? 0 : bits);\n}\n\n/**\n * Clear high bits from an unsigned integer starting with specific bit position\n * @param  a value to clip\n * @param  p bit position to clip at\n * @return clipped value\n */\nstatic av_always_inline av_const unsigned av_mod_uintp2_c(unsigned a, unsigned p)\n{\n    return a & ((1 << p) - 1);\n}\n\n/**\n * Add two signed 32-bit values with saturation.\n *\n * @param  a one value\n * @param  b another value\n * @return sum with signed saturation\n */\nstatic av_always_inline int av_sat_add32_c(int a, int b)\n{\n    return av_clipl_int32((int64_t)a + b);\n}\n\n/**\n * Add a doubled value to another value with saturation at both stages.\n *\n * @param  a first value\n * @param  b value doubled and added to a\n * @return sum with signed saturation\n */\nstatic av_always_inline int av_sat_dadd32_c(int a, int b)\n{\n    return av_sat_add32(a, av_sat_add32(b, b));\n}\n\n/**\n * Clip a float value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const float av_clipf_c(float a, float amin, float amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/**\n * Clip a double value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const double av_clipd_c(double a, double amin, double amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/** Compute ceil(log2(x)).\n * @param x value used to compute ceil(log2(x))\n * @return computed ceiling of log2(x)\n */\nstatic av_always_inline av_const int av_ceil_log2_c(int x)\n{\n    return av_log2((x - 1) << 1);\n}\n\n/**\n * Count number of bits set to one in x\n * @param x value to count bits of\n * @return the number of bits set to one in x\n */\nstatic av_always_inline av_const int av_popcount_c(uint32_t x)\n{\n    x -= (x >> 1) & 0x55555555;\n    x = (x & 0x33333333) + ((x >> 2) & 0x33333333);\n    x = (x + (x >> 4)) & 0x0F0F0F0F;\n    x += x >> 8;\n    return (x + (x >> 16)) & 0x3F;\n}\n\n/**\n * Count number of bits set to one in x\n * @param x value to count bits of\n * @return the number of bits set to one in x\n */\nstatic av_always_inline av_const int av_popcount64_c(uint64_t x)\n{\n    return av_popcount((uint32_t)x) + av_popcount((uint32_t)(x >> 32));\n}\n\nstatic av_always_inline av_const int av_parity_c(uint32_t v)\n{\n    return av_popcount(v) & 1;\n}\n\n#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))\n#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24))\n\n/**\n * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form.\n *\n * @param val      Output value, must be an lvalue of type uint32_t.\n * @param GET_BYTE Expression reading one byte from the input.\n *                 Evaluated up to 7 times (4 for the currently\n *                 assigned Unicode range).  With a memory buffer\n *                 input, this could be *ptr++.\n * @param ERROR    Expression to be evaluated on invalid input,\n *                 typically a goto statement.\n *\n * @warning ERROR should not contain a loop control statement which\n * could interact with the internal while loop, and should force an\n * exit from the macro code (e.g. through a goto or a return) in order\n * to prevent undefined results.\n */\n#define GET_UTF8(val, GET_BYTE, ERROR)\\\n    val= (GET_BYTE);\\\n    {\\\n        uint32_t top = (val & 128) >> 1;\\\n        if ((val & 0xc0) == 0x80 || val >= 0xFE)\\\n            ERROR\\\n        while (val & top) {\\\n            int tmp= (GET_BYTE) - 128;\\\n            if(tmp>>6)\\\n                ERROR\\\n            val= (val<<6) + tmp;\\\n            top <<= 5;\\\n        }\\\n        val &= (top << 1) - 1;\\\n    }\n\n/**\n * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form.\n *\n * @param val       Output value, must be an lvalue of type uint32_t.\n * @param GET_16BIT Expression returning two bytes of UTF-16 data converted\n *                  to native byte order.  Evaluated one or two times.\n * @param ERROR     Expression to be evaluated on invalid input,\n *                  typically a goto statement.\n */\n#define GET_UTF16(val, GET_16BIT, ERROR)\\\n    val = GET_16BIT;\\\n    {\\\n        unsigned int hi = val - 0xD800;\\\n        if (hi < 0x800) {\\\n            val = GET_16BIT - 0xDC00;\\\n            if (val > 0x3FFU || hi > 0x3FFU)\\\n                ERROR\\\n            val += (hi<<10) + 0x10000;\\\n        }\\\n    }\\\n\n/**\n * @def PUT_UTF8(val, tmp, PUT_BYTE)\n * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long).\n * @param val is an input-only argument and should be of type uint32_t. It holds\n * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If\n * val is given as a function it is executed only once.\n * @param tmp is a temporary variable and should be of type uint8_t. It\n * represents an intermediate value during conversion that is to be\n * output by PUT_BYTE.\n * @param PUT_BYTE writes the converted UTF-8 bytes to any proper destination.\n * It could be a function or a statement, and uses tmp as the input byte.\n * For example, PUT_BYTE could be \"*output++ = tmp;\" PUT_BYTE will be\n * executed up to 4 times for values in the valid UTF-8 range and up to\n * 7 times in the general case, depending on the length of the converted\n * Unicode character.\n */\n#define PUT_UTF8(val, tmp, PUT_BYTE)\\\n    {\\\n        int bytes, shift;\\\n        uint32_t in = val;\\\n        if (in < 0x80) {\\\n            tmp = in;\\\n            PUT_BYTE\\\n        } else {\\\n            bytes = (av_log2(in) + 4) / 5;\\\n            shift = (bytes - 1) * 6;\\\n            tmp = (256 - (256 >> bytes)) | (in >> shift);\\\n            PUT_BYTE\\\n            while (shift >= 6) {\\\n                shift -= 6;\\\n                tmp = 0x80 | ((in >> shift) & 0x3f);\\\n                PUT_BYTE\\\n            }\\\n        }\\\n    }\n\n/**\n * @def PUT_UTF16(val, tmp, PUT_16BIT)\n * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes).\n * @param val is an input-only argument and should be of type uint32_t. It holds\n * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If\n * val is given as a function it is executed only once.\n * @param tmp is a temporary variable and should be of type uint16_t. It\n * represents an intermediate value during conversion that is to be\n * output by PUT_16BIT.\n * @param PUT_16BIT writes the converted UTF-16 data to any proper destination\n * in desired endianness. It could be a function or a statement, and uses tmp\n * as the input byte.  For example, PUT_BYTE could be \"*output++ = tmp;\"\n * PUT_BYTE will be executed 1 or 2 times depending on input character.\n */\n#define PUT_UTF16(val, tmp, PUT_16BIT)\\\n    {\\\n        uint32_t in = val;\\\n        if (in < 0x10000) {\\\n            tmp = in;\\\n            PUT_16BIT\\\n        } else {\\\n            tmp = 0xD800 | ((in - 0x10000) >> 10);\\\n            PUT_16BIT\\\n            tmp = 0xDC00 | ((in - 0x10000) & 0x3FF);\\\n            PUT_16BIT\\\n        }\\\n    }\\\n\n\n\n#include \"mem.h\"\n\n#ifdef HAVE_AV_CONFIG_H\n#    include \"internal.h\"\n#endif /* HAVE_AV_CONFIG_H */\n\n#endif /* AVUTIL_COMMON_H */\n\n/*\n * The following definitions are outside the multiple inclusion guard\n * to ensure they are immediately available in intmath.h.\n */\n\n#ifndef av_ceil_log2\n#   define av_ceil_log2     av_ceil_log2_c\n#endif\n#ifndef av_clip\n#   define av_clip          av_clip_c\n#endif\n#ifndef av_clip64\n#   define av_clip64        av_clip64_c\n#endif\n#ifndef av_clip_uint8\n#   define av_clip_uint8    av_clip_uint8_c\n#endif\n#ifndef av_clip_int8\n#   define av_clip_int8     av_clip_int8_c\n#endif\n#ifndef av_clip_uint16\n#   define av_clip_uint16   av_clip_uint16_c\n#endif\n#ifndef av_clip_int16\n#   define av_clip_int16    av_clip_int16_c\n#endif\n#ifndef av_clipl_int32\n#   define av_clipl_int32   av_clipl_int32_c\n#endif\n#ifndef av_clip_intp2\n#   define av_clip_intp2    av_clip_intp2_c\n#endif\n#ifndef av_clip_uintp2\n#   define av_clip_uintp2   av_clip_uintp2_c\n#endif\n#ifndef av_mod_uintp2\n#   define av_mod_uintp2    av_mod_uintp2_c\n#endif\n#ifndef av_sat_add32\n#   define av_sat_add32     av_sat_add32_c\n#endif\n#ifndef av_sat_dadd32\n#   define av_sat_dadd32    av_sat_dadd32_c\n#endif\n#ifndef av_clipf\n#   define av_clipf         av_clipf_c\n#endif\n#ifndef av_clipd\n#   define av_clipd         av_clipd_c\n#endif\n#ifndef av_popcount\n#   define av_popcount      av_popcount_c\n#endif\n#ifndef av_popcount64\n#   define av_popcount64    av_popcount64_c\n#endif\n#ifndef av_parity\n#   define av_parity        av_parity_c\n#endif\n"
  },
  {
    "path": "ffmpeg-3.3.3-experimental-patch/hevcdsp_template.before.c",
    "content": "/*\n * HEVC video decoder\n *\n * Copyright (C) 2012 - 2013 Guillaume Martres\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"get_bits.h\"\n#include \"hevcdec.h\"\n\n#include \"bit_depth_template.c\"\n#include \"hevcdsp.h\"\n\nstatic void FUNC(put_pcm)(uint8_t *_dst, ptrdiff_t stride, int width, int height,\n                          GetBitContext *gb, int pcm_bit_depth)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n\n    stride /= sizeof(pixel);\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = get_bits(gb, pcm_bit_depth) << (BIT_DEPTH - pcm_bit_depth);\n        dst += stride;\n    }\n}\n\nstatic av_always_inline void FUNC(add_residual)(uint8_t *_dst, int16_t *res,\n                                                ptrdiff_t stride, int size)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n\n    stride /= sizeof(pixel);\n\n    for (y = 0; y < size; y++) {\n        for (x = 0; x < size; x++) {\n            dst[x] = av_clip_pixel(dst[x] + *res);\n            res++;\n        }\n        dst += stride;\n    }\n}\n\nstatic void FUNC(add_residual4x4)(uint8_t *_dst, int16_t *res,\n                                  ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 4);\n}\n\nstatic void FUNC(add_residual8x8)(uint8_t *_dst, int16_t *res,\n                                  ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 8);\n}\n\nstatic void FUNC(add_residual16x16)(uint8_t *_dst, int16_t *res,\n                                    ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 16);\n}\n\nstatic void FUNC(add_residual32x32)(uint8_t *_dst, int16_t *res,\n                                    ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 32);\n}\n\nstatic void FUNC(transform_rdpcm)(int16_t *_coeffs, int16_t log2_size, int mode)\n{\n    int16_t *coeffs = (int16_t *) _coeffs;\n    int x, y;\n    int size = 1 << log2_size;\n\n    if (mode) {\n        coeffs += size;\n        for (y = 0; y < size - 1; y++) {\n            for (x = 0; x < size; x++)\n                coeffs[x] += coeffs[x - size];\n            coeffs += size;\n        }\n    } else {\n        for (y = 0; y < size; y++) {\n            for (x = 1; x < size; x++)\n                coeffs[x] += coeffs[x - 1];\n            coeffs += size;\n        }\n    }\n}\n\nstatic void FUNC(dequant)(int16_t *coeffs, int16_t log2_size)\n{\n    int shift  = 15 - BIT_DEPTH - log2_size;\n    int x, y;\n    int size = 1 << log2_size;\n\n    if (shift > 0) {\n        int offset = 1 << (shift - 1);\n        for (y = 0; y < size; y++) {\n            for (x = 0; x < size; x++) {\n                *coeffs = (*coeffs + offset) >> shift;\n                coeffs++;\n            }\n        }\n    } else {\n        for (y = 0; y < size; y++) {\n            for (x = 0; x < size; x++) {\n                *coeffs = *coeffs << -shift;\n                coeffs++;\n            }\n        }\n    }\n}\n\n#define SET(dst, x)   (dst) = (x)\n#define SCALE(dst, x) (dst) = av_clip_int16(((x) + add) >> shift)\n\n#define TR_4x4_LUMA(dst, src, step, assign)                             \\\n    do {                                                                \\\n        int c0 = src[0 * step] + src[2 * step];                         \\\n        int c1 = src[2 * step] + src[3 * step];                         \\\n        int c2 = src[0 * step] - src[3 * step];                         \\\n        int c3 = 74 * src[1 * step];                                    \\\n                                                                        \\\n        assign(dst[2 * step], 74 * (src[0 * step] -                     \\\n                                    src[2 * step] +                     \\\n                                    src[3 * step]));                    \\\n        assign(dst[0 * step], 29 * c0 + 55 * c1 + c3);                  \\\n        assign(dst[1 * step], 55 * c2 - 29 * c1 + c3);                  \\\n        assign(dst[3 * step], 55 * c0 + 29 * c2 - c3);                  \\\n    } while (0)\n\nstatic void FUNC(transform_4x4_luma)(int16_t *coeffs)\n{\n    int i;\n    int shift    = 7;\n    int add      = 1 << (shift - 1);\n    int16_t *src = coeffs;\n\n    for (i = 0; i < 4; i++) {\n        TR_4x4_LUMA(src, src, 4, SCALE);\n        src++;\n    }\n\n    shift = 20 - BIT_DEPTH;\n    add   = 1 << (shift - 1);\n    for (i = 0; i < 4; i++) {\n        TR_4x4_LUMA(coeffs, coeffs, 1, SCALE);\n        coeffs += 4;\n    }\n}\n\n#undef TR_4x4_LUMA\n\n#define TR_4(dst, src, dstep, sstep, assign, end)                 \\\n    do {                                                          \\\n        const int e0 = 64 * src[0 * sstep] + 64 * src[2 * sstep]; \\\n        const int e1 = 64 * src[0 * sstep] - 64 * src[2 * sstep]; \\\n        const int o0 = 83 * src[1 * sstep] + 36 * src[3 * sstep]; \\\n        const int o1 = 36 * src[1 * sstep] - 83 * src[3 * sstep]; \\\n                                                                  \\\n        assign(dst[0 * dstep], e0 + o0);                          \\\n        assign(dst[1 * dstep], e1 + o1);                          \\\n        assign(dst[2 * dstep], e1 - o1);                          \\\n        assign(dst[3 * dstep], e0 - o0);                          \\\n    } while (0)\n\n#define TR_8(dst, src, dstep, sstep, assign, end)                 \\\n    do {                                                          \\\n        int i, j;                                                 \\\n        int e_8[4];                                               \\\n        int o_8[4] = { 0 };                                       \\\n        for (i = 0; i < 4; i++)                                   \\\n            for (j = 1; j < end; j += 2)                          \\\n                o_8[i] += transform[4 * j][i] * src[j * sstep];   \\\n        TR_4(e_8, src, 1, 2 * sstep, SET, 4);                     \\\n                                                                  \\\n        for (i = 0; i < 4; i++) {                                 \\\n            assign(dst[i * dstep], e_8[i] + o_8[i]);              \\\n            assign(dst[(7 - i) * dstep], e_8[i] - o_8[i]);        \\\n        }                                                         \\\n    } while (0)\n\n#define TR_16(dst, src, dstep, sstep, assign, end)                \\\n    do {                                                          \\\n        int i, j;                                                 \\\n        int e_16[8];                                              \\\n        int o_16[8] = { 0 };                                      \\\n        for (i = 0; i < 8; i++)                                   \\\n            for (j = 1; j < end; j += 2)                          \\\n                o_16[i] += transform[2 * j][i] * src[j * sstep];  \\\n        TR_8(e_16, src, 1, 2 * sstep, SET, 8);                    \\\n                                                                  \\\n        for (i = 0; i < 8; i++) {                                 \\\n            assign(dst[i * dstep], e_16[i] + o_16[i]);            \\\n            assign(dst[(15 - i) * dstep], e_16[i] - o_16[i]);     \\\n        }                                                         \\\n    } while (0)\n\n#define TR_32(dst, src, dstep, sstep, assign, end)                \\\n    do {                                                          \\\n        int i, j;                                                 \\\n        int e_32[16];                                             \\\n        int o_32[16] = { 0 };                                     \\\n        for (i = 0; i < 16; i++)                                  \\\n            for (j = 1; j < end; j += 2)                          \\\n                o_32[i] += transform[j][i] * src[j * sstep];      \\\n        TR_16(e_32, src, 1, 2 * sstep, SET, end / 2);             \\\n                                                                  \\\n        for (i = 0; i < 16; i++) {                                \\\n            assign(dst[i * dstep], e_32[i] + o_32[i]);            \\\n            assign(dst[(31 - i) * dstep], e_32[i] - o_32[i]);     \\\n        }                                                         \\\n    } while (0)\n\n#define IDCT_VAR4(H)                                              \\\n    int limit2 = FFMIN(col_limit + 4, H)\n#define IDCT_VAR8(H)                                              \\\n    int limit  = FFMIN(col_limit, H);                             \\\n    int limit2 = FFMIN(col_limit + 4, H)\n#define IDCT_VAR16(H)   IDCT_VAR8(H)\n#define IDCT_VAR32(H)   IDCT_VAR8(H)\n\n#define IDCT(H)                                                   \\\nstatic void FUNC(idct_ ## H ## x ## H )(int16_t *coeffs,          \\\n                                        int col_limit)            \\\n{                                                                 \\\n    int i;                                                        \\\n    int      shift = 7;                                           \\\n    int      add   = 1 << (shift - 1);                            \\\n    int16_t *src   = coeffs;                                      \\\n    IDCT_VAR ## H(H);                                             \\\n                                                                  \\\n    for (i = 0; i < H; i++) {                                     \\\n        TR_ ## H(src, src, H, H, SCALE, limit2);                  \\\n        if (limit2 < H && i%4 == 0 && !!i)                        \\\n            limit2 -= 4;                                          \\\n        src++;                                                    \\\n    }                                                             \\\n                                                                  \\\n    shift = 20 - BIT_DEPTH;                                       \\\n    add   = 1 << (shift - 1);                                     \\\n    for (i = 0; i < H; i++) {                                     \\\n        TR_ ## H(coeffs, coeffs, 1, 1, SCALE, limit);             \\\n        coeffs += H;                                              \\\n    }                                                             \\\n}\n\n#define IDCT_DC(H)                                                \\\nstatic void FUNC(idct_ ## H ## x ## H ## _dc)(int16_t *coeffs)    \\\n{                                                                 \\\n    int i, j;                                                     \\\n    int shift = 14 - BIT_DEPTH;                                   \\\n    int add   = 1 << (shift - 1);                                 \\\n    int coeff = (((coeffs[0] + 1) >> 1) + add) >> shift;          \\\n                                                                  \\\n    for (j = 0; j < H; j++) {                                     \\\n        for (i = 0; i < H; i++) {                                 \\\n            coeffs[i + j * H] = coeff;                            \\\n        }                                                         \\\n    }                                                             \\\n}\n\nIDCT( 4)\nIDCT( 8)\nIDCT(16)\nIDCT(32)\n\nIDCT_DC( 4)\nIDCT_DC( 8)\nIDCT_DC(16)\nIDCT_DC(32)\n\n#undef TR_4\n#undef TR_8\n#undef TR_16\n#undef TR_32\n\n#undef SET\n#undef SCALE\n\nstatic void FUNC(sao_band_filter)(uint8_t *_dst, uint8_t *_src,\n                                  ptrdiff_t stride_dst, ptrdiff_t stride_src,\n                                  int16_t *sao_offset_val, int sao_left_class,\n                                  int width, int height)\n{\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int offset_table[32] = { 0 };\n    int k, y, x;\n    int shift  = BIT_DEPTH - 5;\n\n    stride_dst /= sizeof(pixel);\n    stride_src /= sizeof(pixel);\n\n    for (k = 0; k < 4; k++)\n        offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1];\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(src[x] + offset_table[src[x] >> shift]);\n        dst += stride_dst;\n        src += stride_src;\n    }\n}\n\n#define CMP(a, b) (((a) > (b)) - ((a) < (b)))\n\nstatic void FUNC(sao_edge_filter)(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val,\n                                  int eo, int width, int height) {\n\n    static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 };\n    static const int8_t pos[4][2][2] = {\n        { { -1,  0 }, {  1, 0 } }, // horizontal\n        { {  0, -1 }, {  0, 1 } }, // vertical\n        { { -1, -1 }, {  1, 1 } }, // 45 degree\n        { {  1, -1 }, { -1, 1 } }, // 135 degree\n    };\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int a_stride, b_stride;\n    int x, y;\n    ptrdiff_t stride_src = (2*MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE) / sizeof(pixel);\n    stride_dst /= sizeof(pixel);\n\n    a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src;\n    b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src;\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            int diff0 = CMP(src[x], src[x + a_stride]);\n            int diff1 = CMP(src[x], src[x + b_stride]);\n            int offset_val        = edge_idx[2 + diff0 + diff1];\n            dst[x] = av_clip_pixel(src[x] + sao_offset_val[offset_val]);\n        }\n        src += stride_src;\n        dst += stride_dst;\n    }\n}\n\nstatic void FUNC(sao_edge_restore_0)(uint8_t *_dst, uint8_t *_src,\n                                    ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao,\n                                    int *borders, int _width, int _height,\n                                    int c_idx, uint8_t *vert_edge,\n                                    uint8_t *horiz_edge, uint8_t *diag_edge)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int16_t *sao_offset_val = sao->offset_val[c_idx];\n    int sao_eo_class    = sao->eo_class[c_idx];\n    int init_x = 0, width = _width, height = _height;\n\n    stride_dst /= sizeof(pixel);\n    stride_src /= sizeof(pixel);\n\n    if (sao_eo_class != SAO_EO_VERT) {\n        if (borders[0]) {\n            int offset_val = sao_offset_val[0];\n            for (y = 0; y < height; y++) {\n                dst[y * stride_dst] = av_clip_pixel(src[y * stride_src] + offset_val);\n            }\n            init_x = 1;\n        }\n        if (borders[2]) {\n            int offset_val = sao_offset_val[0];\n            int offset     = width - 1;\n            for (x = 0; x < height; x++) {\n                dst[x * stride_dst + offset] = av_clip_pixel(src[x * stride_src + offset] + offset_val);\n            }\n            width--;\n        }\n    }\n    if (sao_eo_class != SAO_EO_HORIZ) {\n        if (borders[1]) {\n            int offset_val = sao_offset_val[0];\n            for (x = init_x; x < width; x++)\n                dst[x] = av_clip_pixel(src[x] + offset_val);\n        }\n        if (borders[3]) {\n            int offset_val   = sao_offset_val[0];\n            ptrdiff_t y_stride_dst = stride_dst * (height - 1);\n            ptrdiff_t y_stride_src = stride_src * (height - 1);\n            for (x = init_x; x < width; x++)\n                dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + offset_val);\n            height--;\n        }\n    }\n}\n\nstatic void FUNC(sao_edge_restore_1)(uint8_t *_dst, uint8_t *_src,\n                                    ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao,\n                                    int *borders, int _width, int _height,\n                                    int c_idx, uint8_t *vert_edge,\n                                    uint8_t *horiz_edge, uint8_t *diag_edge)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int16_t *sao_offset_val = sao->offset_val[c_idx];\n    int sao_eo_class    = sao->eo_class[c_idx];\n    int init_x = 0, init_y = 0, width = _width, height = _height;\n\n    stride_dst /= sizeof(pixel);\n    stride_src /= sizeof(pixel);\n\n    if (sao_eo_class != SAO_EO_VERT) {\n        if (borders[0]) {\n            int offset_val = sao_offset_val[0];\n            for (y = 0; y < height; y++) {\n                dst[y * stride_dst] = av_clip_pixel(src[y * stride_src] + offset_val);\n            }\n            init_x = 1;\n        }\n        if (borders[2]) {\n            int offset_val = sao_offset_val[0];\n            int offset     = width - 1;\n            for (x = 0; x < height; x++) {\n                dst[x * stride_dst + offset] = av_clip_pixel(src[x * stride_src + offset] + offset_val);\n            }\n            width--;\n        }\n    }\n    if (sao_eo_class != SAO_EO_HORIZ) {\n        if (borders[1]) {\n            int offset_val = sao_offset_val[0];\n            for (x = init_x; x < width; x++)\n                dst[x] = av_clip_pixel(src[x] + offset_val);\n            init_y = 1;\n        }\n        if (borders[3]) {\n            int offset_val   = sao_offset_val[0];\n            ptrdiff_t y_stride_dst = stride_dst * (height - 1);\n            ptrdiff_t y_stride_src = stride_src * (height - 1);\n            for (x = init_x; x < width; x++)\n                dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + offset_val);\n            height--;\n        }\n    }\n\n    {\n        int save_upper_left  = !diag_edge[0] && sao_eo_class == SAO_EO_135D && !borders[0] && !borders[1];\n        int save_upper_right = !diag_edge[1] && sao_eo_class == SAO_EO_45D  && !borders[1] && !borders[2];\n        int save_lower_right = !diag_edge[2] && sao_eo_class == SAO_EO_135D && !borders[2] && !borders[3];\n        int save_lower_left  = !diag_edge[3] && sao_eo_class == SAO_EO_45D  && !borders[0] && !borders[3];\n\n        // Restore pixels that can't be modified\n        if(vert_edge[0] && sao_eo_class != SAO_EO_VERT) {\n            for(y = init_y+save_upper_left; y< height-save_lower_left; y++)\n                dst[y*stride_dst] = src[y*stride_src];\n        }\n        if(vert_edge[1] && sao_eo_class != SAO_EO_VERT) {\n            for(y = init_y+save_upper_right; y< height-save_lower_right; y++)\n                dst[y*stride_dst+width-1] = src[y*stride_src+width-1];\n        }\n\n        if(horiz_edge[0] && sao_eo_class != SAO_EO_HORIZ) {\n            for(x = init_x+save_upper_left; x < width-save_upper_right; x++)\n                dst[x] = src[x];\n        }\n        if(horiz_edge[1] && sao_eo_class != SAO_EO_HORIZ) {\n            for(x = init_x+save_lower_left; x < width-save_lower_right; x++)\n                dst[(height-1)*stride_dst+x] = src[(height-1)*stride_src+x];\n        }\n        if(diag_edge[0] && sao_eo_class == SAO_EO_135D)\n            dst[0] = src[0];\n        if(diag_edge[1] && sao_eo_class == SAO_EO_45D)\n            dst[width-1] = src[width-1];\n        if(diag_edge[2] && sao_eo_class == SAO_EO_135D)\n            dst[stride_dst*(height-1)+width-1] = src[stride_src*(height-1)+width-1];\n        if(diag_edge[3] && sao_eo_class == SAO_EO_45D)\n            dst[stride_dst*(height-1)] = src[stride_src*(height-1)];\n\n    }\n}\n\n#undef CMP\n\n////////////////////////////////////////////////////////////////////////////////\n//\n////////////////////////////////////////////////////////////////////////////////\nstatic void FUNC(put_hevc_pel_pixels)(int16_t *dst,\n                                      uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = src[x] << (14 - BIT_DEPTH);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_uni_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                          int height, intptr_t mx, intptr_t my, int width)\n{\n    int y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    for (y = 0; y < height; y++) {\n        memcpy(dst, src, width * sizeof(pixel));\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_bi_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                         int16_t *src2,\n                                         int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14  + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((src[x] << (14 - BIT_DEPTH)) + src2[x] + offset) >> shift);\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_uni_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                            int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((src[x] << (14 - BIT_DEPTH)) * wx + offset) >> shift) + ox);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_bi_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                           int16_t *src2,\n                                           int height, int denom, int wx0, int wx1,\n                                           int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14  + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel(( (src[x] << (14 - BIT_DEPTH)) * wx1 + src2[x] * wx0 + ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));\n        }\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//\n////////////////////////////////////////////////////////////////////////////////\n#define QPEL_FILTER(src, stride)                                               \\\n    (filter[0] * src[x - 3 * stride] +                                         \\\n     filter[1] * src[x - 2 * stride] +                                         \\\n     filter[2] * src[x -     stride] +                                         \\\n     filter[3] * src[x             ] +                                         \\\n     filter[4] * src[x +     stride] +                                         \\\n     filter[5] * src[x + 2 * stride] +                                         \\\n     filter[6] * src[x + 3 * stride] +                                         \\\n     filter[7] * src[x + 4 * stride])\n\nstatic void FUNC(put_hevc_qpel_h)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    const int8_t *filter    = ff_hevc_qpel_filters[mx - 1];\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_v)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    const int8_t *filter    = ff_hevc_qpel_filters[my - 1];\n    for (y = 0; y < height; y++)  {\n        for (x = 0; x < width; x++)\n            dst[x] = QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_hv)(int16_t *dst,\n                                   uint8_t *_src,\n                                   ptrdiff_t _srcstride,\n                                   int height, intptr_t mx,\n                                   intptr_t my, int width)\n{\n    int x, y;\n    const int8_t *filter;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n    filter = ff_hevc_qpel_filters[mx - 1];\n    for (y = 0; y < height + QPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_qpel_filters[my - 1];\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6;\n        tmp += MAX_PB_SIZE;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_uni_h)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                      uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter    = ff_hevc_qpel_filters[mx - 1];\n    int shift = 14 - BIT_DEPTH;\n\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + offset) >> shift);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    const int8_t *filter    = ff_hevc_qpel_filters[mx - 1];\n\n    int shift = 14  + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_uni_v)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                     uint8_t *_src, ptrdiff_t _srcstride,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter    = ff_hevc_qpel_filters[my - 1];\n    int shift = 14 - BIT_DEPTH;\n\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + offset) >> shift);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\n\nstatic void FUNC(put_hevc_qpel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    const int8_t *filter    = ff_hevc_qpel_filters[my - 1];\n\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_uni_hv)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                       uint8_t *_src, ptrdiff_t _srcstride,\n                                       int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    const int8_t *filter;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift =  14 - BIT_DEPTH;\n\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n    filter = ff_hevc_qpel_filters[mx - 1];\n    for (y = 0; y < height + QPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_qpel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + offset) >> shift);\n        tmp += MAX_PB_SIZE;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int16_t *src2,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    const int8_t *filter;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n    filter = ff_hevc_qpel_filters[mx - 1];\n    for (y = 0; y < height + QPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_qpel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift);\n        tmp  += MAX_PB_SIZE;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_uni_w_h)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                        uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox,\n                                        intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter    = ff_hevc_qpel_filters[mx - 1];\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    const int8_t *filter    = ff_hevc_qpel_filters[mx - 1];\n\n    int shift = 14  + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_uni_w_v)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                        uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox,\n                                        intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter    = ff_hevc_qpel_filters[my - 1];\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    const int8_t *filter    = ff_hevc_qpel_filters[my - 1];\n\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_uni_w_hv)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                         uint8_t *_src, ptrdiff_t _srcstride,\n                                         int height, int denom, int wx, int ox,\n                                         intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    const int8_t *filter;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n    filter = ff_hevc_qpel_filters[mx - 1];\n    for (y = 0; y < height + QPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_qpel_filters[my - 1];\n\n    ox = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx + offset) >> shift) + ox);\n        tmp += MAX_PB_SIZE;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int16_t *src2,\n                                        int height, int denom, int wx0, int wx1,\n                                        int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    const int8_t *filter;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n    filter = ff_hevc_qpel_filters[mx - 1];\n    for (y = 0; y < height + QPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_qpel_filters[my - 1];\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));\n        tmp  += MAX_PB_SIZE;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//\n////////////////////////////////////////////////////////////////////////////////\n#define EPEL_FILTER(src, stride)                                               \\\n    (filter[0] * src[x - stride] +                                             \\\n     filter[1] * src[x]          +                                             \\\n     filter[2] * src[x + stride] +                                             \\\n     filter[3] * src[x + 2 * stride])\n\nstatic void FUNC(put_hevc_epel_h)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_v)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_hv)(int16_t *dst,\n                                   uint8_t *_src, ptrdiff_t _srcstride,\n                                   int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6;\n        tmp += MAX_PB_SIZE;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + offset) >> shift);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);\n        }\n        dst  += dststride;\n        src  += srcstride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    int shift = 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + offset) >> shift);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);\n        dst  += dststride;\n        src  += srcstride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + offset) >> shift);\n        tmp += MAX_PB_SIZE;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int16_t *src2,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift);\n        tmp  += MAX_PB_SIZE;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel((((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);\n        }\n        dst += dststride;\n        src += srcstride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel((((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);\n        }\n        dst += dststride;\n        src += srcstride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                         int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx + offset) >> shift) + ox);\n        tmp += MAX_PB_SIZE;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int16_t *src2,\n                                        int height, int denom, int wx0, int wx1,\n                                        int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));\n        tmp  += MAX_PB_SIZE;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\n// line zero\n#define P3 pix[-4 * xstride]\n#define P2 pix[-3 * xstride]\n#define P1 pix[-2 * xstride]\n#define P0 pix[-1 * xstride]\n#define Q0 pix[0 * xstride]\n#define Q1 pix[1 * xstride]\n#define Q2 pix[2 * xstride]\n#define Q3 pix[3 * xstride]\n\n// line three. used only for deblocking decision\n#define TP3 pix[-4 * xstride + 3 * ystride]\n#define TP2 pix[-3 * xstride + 3 * ystride]\n#define TP1 pix[-2 * xstride + 3 * ystride]\n#define TP0 pix[-1 * xstride + 3 * ystride]\n#define TQ0 pix[0  * xstride + 3 * ystride]\n#define TQ1 pix[1  * xstride + 3 * ystride]\n#define TQ2 pix[2  * xstride + 3 * ystride]\n#define TQ3 pix[3  * xstride + 3 * ystride]\n\nstatic void FUNC(hevc_loop_filter_luma)(uint8_t *_pix,\n                                        ptrdiff_t _xstride, ptrdiff_t _ystride,\n                                        int beta, int *_tc,\n                                        uint8_t *_no_p, uint8_t *_no_q)\n{\n    int d, j;\n    pixel *pix        = (pixel *)_pix;\n    ptrdiff_t xstride = _xstride / sizeof(pixel);\n    ptrdiff_t ystride = _ystride / sizeof(pixel);\n\n    beta <<= BIT_DEPTH - 8;\n\n    for (j = 0; j < 2; j++) {\n        const int dp0  = abs(P2  - 2 * P1  + P0);\n        const int dq0  = abs(Q2  - 2 * Q1  + Q0);\n        const int dp3  = abs(TP2 - 2 * TP1 + TP0);\n        const int dq3  = abs(TQ2 - 2 * TQ1 + TQ0);\n        const int d0   = dp0 + dq0;\n        const int d3   = dp3 + dq3;\n        const int tc   = _tc[j]   << (BIT_DEPTH - 8);\n        const int no_p = _no_p[j];\n        const int no_q = _no_q[j];\n\n        if (d0 + d3 >= beta) {\n            pix += 4 * ystride;\n            continue;\n        } else {\n            const int beta_3 = beta >> 3;\n            const int beta_2 = beta >> 2;\n            const int tc25   = ((tc * 5 + 1) >> 1);\n\n            if (abs(P3  -  P0) + abs(Q3  -  Q0) < beta_3 && abs(P0  -  Q0) < tc25 &&\n                abs(TP3 - TP0) + abs(TQ3 - TQ0) < beta_3 && abs(TP0 - TQ0) < tc25 &&\n                                      (d0 << 1) < beta_2 &&      (d3 << 1) < beta_2) {\n                // strong filtering\n                const int tc2 = tc << 1;\n                for (d = 0; d < 4; d++) {\n                    const int p3 = P3;\n                    const int p2 = P2;\n                    const int p1 = P1;\n                    const int p0 = P0;\n                    const int q0 = Q0;\n                    const int q1 = Q1;\n                    const int q2 = Q2;\n                    const int q3 = Q3;\n                    if (!no_p) {\n                        P0 = p0 + av_clip(((p2 + 2 * p1 + 2 * p0 + 2 * q0 + q1 + 4) >> 3) - p0, -tc2, tc2);\n                        P1 = p1 + av_clip(((p2 + p1 + p0 + q0 + 2) >> 2) - p1, -tc2, tc2);\n                        P2 = p2 + av_clip(((2 * p3 + 3 * p2 + p1 + p0 + q0 + 4) >> 3) - p2, -tc2, tc2);\n                    }\n                    if (!no_q) {\n                        Q0 = q0 + av_clip(((p1 + 2 * p0 + 2 * q0 + 2 * q1 + q2 + 4) >> 3) - q0, -tc2, tc2);\n                        Q1 = q1 + av_clip(((p0 + q0 + q1 + q2 + 2) >> 2) - q1, -tc2, tc2);\n                        Q2 = q2 + av_clip(((2 * q3 + 3 * q2 + q1 + q0 + p0 + 4) >> 3) - q2, -tc2, tc2);\n                    }\n                    pix += ystride;\n                }\n            } else { // normal filtering\n                int nd_p = 1;\n                int nd_q = 1;\n                const int tc_2 = tc >> 1;\n                if (dp0 + dp3 < ((beta + (beta >> 1)) >> 3))\n                    nd_p = 2;\n                if (dq0 + dq3 < ((beta + (beta >> 1)) >> 3))\n                    nd_q = 2;\n\n                for (d = 0; d < 4; d++) {\n                    const int p2 = P2;\n                    const int p1 = P1;\n                    const int p0 = P0;\n                    const int q0 = Q0;\n                    const int q1 = Q1;\n                    const int q2 = Q2;\n                    int delta0   = (9 * (q0 - p0) - 3 * (q1 - p1) + 8) >> 4;\n                    if (abs(delta0) < 10 * tc) {\n                        delta0 = av_clip(delta0, -tc, tc);\n                        if (!no_p)\n                            P0 = av_clip_pixel(p0 + delta0);\n                        if (!no_q)\n                            Q0 = av_clip_pixel(q0 - delta0);\n                        if (!no_p && nd_p > 1) {\n                            const int deltap1 = av_clip((((p2 + p0 + 1) >> 1) - p1 + delta0) >> 1, -tc_2, tc_2);\n                            P1 = av_clip_pixel(p1 + deltap1);\n                        }\n                        if (!no_q && nd_q > 1) {\n                            const int deltaq1 = av_clip((((q2 + q0 + 1) >> 1) - q1 - delta0) >> 1, -tc_2, tc_2);\n                            Q1 = av_clip_pixel(q1 + deltaq1);\n                        }\n                    }\n                    pix += ystride;\n                }\n            }\n        }\n    }\n}\n\nstatic void FUNC(hevc_loop_filter_chroma)(uint8_t *_pix, ptrdiff_t _xstride,\n                                          ptrdiff_t _ystride, int *_tc,\n                                          uint8_t *_no_p, uint8_t *_no_q)\n{\n    int d, j, no_p, no_q;\n    pixel *pix        = (pixel *)_pix;\n    ptrdiff_t xstride = _xstride / sizeof(pixel);\n    ptrdiff_t ystride = _ystride / sizeof(pixel);\n\n    for (j = 0; j < 2; j++) {\n        const int tc = _tc[j] << (BIT_DEPTH - 8);\n        if (tc <= 0) {\n            pix += 4 * ystride;\n            continue;\n        }\n        no_p = _no_p[j];\n        no_q = _no_q[j];\n\n        for (d = 0; d < 4; d++) {\n            int delta0;\n            const int p1 = P1;\n            const int p0 = P0;\n            const int q0 = Q0;\n            const int q1 = Q1;\n            delta0 = av_clip((((q0 - p0) * 4) + p1 - q1 + 4) >> 3, -tc, tc);\n            if (!no_p)\n                P0 = av_clip_pixel(p0 + delta0);\n            if (!no_q)\n                Q0 = av_clip_pixel(q0 - delta0);\n            pix += ystride;\n        }\n    }\n}\n\nstatic void FUNC(hevc_h_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,\n                                            int32_t *tc, uint8_t *no_p,\n                                            uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_chroma)(pix, stride, sizeof(pixel), tc, no_p, no_q);\n}\n\nstatic void FUNC(hevc_v_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,\n                                            int32_t *tc, uint8_t *no_p,\n                                            uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_chroma)(pix, sizeof(pixel), stride, tc, no_p, no_q);\n}\n\nstatic void FUNC(hevc_h_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,\n                                          int beta, int32_t *tc, uint8_t *no_p,\n                                          uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_luma)(pix, stride, sizeof(pixel),\n                                beta, tc, no_p, no_q);\n}\n\nstatic void FUNC(hevc_v_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,\n                                          int beta, int32_t *tc, uint8_t *no_p,\n                                          uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_luma)(pix, sizeof(pixel), stride,\n                                beta, tc, no_p, no_q);\n}\n\n#undef P3\n#undef P2\n#undef P1\n#undef P0\n#undef Q0\n#undef Q1\n#undef Q2\n#undef Q3\n\n#undef TP3\n#undef TP2\n#undef TP1\n#undef TP0\n#undef TQ0\n#undef TQ1\n#undef TQ2\n#undef TQ3\n"
  },
  {
    "path": "ffmpeg-3.3.3-experimental-patch/hevcdsp_template.c",
    "content": "/*\n * HEVC video decoder\n *\n * Copyright (C) 2012 - 2013 Guillaume Martres\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifdef _MSC_VER\n#include <emmintrin.h>\n#endif\n\n#include \"get_bits.h\"\n#include \"hevcdec.h\"\n\n#include \"bit_depth_template.c\"\n#include \"hevcdsp.h\"\n\nstatic void FUNC(put_pcm)(uint8_t *_dst, ptrdiff_t stride, int width, int height,\n                          GetBitContext *gb, int pcm_bit_depth)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n\n    stride /= sizeof(pixel);\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = get_bits(gb, pcm_bit_depth) << (BIT_DEPTH - pcm_bit_depth);\n        dst += stride;\n    }\n}\n\nstatic av_always_inline void FUNC(add_residual)(uint8_t *_dst, int16_t *res,\n                                                ptrdiff_t stride, int size)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n\n    stride /= sizeof(pixel);\n\n    for (y = 0; y < size; y++) {\n        for (x = 0; x < size; x++) {\n            dst[x] = av_clip_pixel(dst[x] + *res);\n            res++;\n        }\n        dst += stride;\n    }\n}\n\nstatic void FUNC(add_residual4x4)(uint8_t *_dst, int16_t *res,\n                                  ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 4);\n}\n\nstatic void FUNC(add_residual8x8)(uint8_t *_dst, int16_t *res,\n                                  ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 8);\n}\n\nstatic void FUNC(add_residual16x16)(uint8_t *_dst, int16_t *res,\n                                    ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 16);\n}\n\nstatic void FUNC(add_residual32x32)(uint8_t *_dst, int16_t *res,\n                                    ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 32);\n}\n\nstatic void FUNC(transform_rdpcm)(int16_t *_coeffs, int16_t log2_size, int mode)\n{\n    int16_t *coeffs = (int16_t *) _coeffs;\n    int x, y;\n    int size = 1 << log2_size;\n\n    if (mode) {\n        coeffs += size;\n        for (y = 0; y < size - 1; y++) {\n            for (x = 0; x < size; x++)\n                coeffs[x] += coeffs[x - size];\n            coeffs += size;\n        }\n    } else {\n        for (y = 0; y < size; y++) {\n            for (x = 1; x < size; x++)\n                coeffs[x] += coeffs[x - 1];\n            coeffs += size;\n        }\n    }\n}\n\nstatic void FUNC(dequant)(int16_t *coeffs, int16_t log2_size)\n{\n    int shift  = 15 - BIT_DEPTH - log2_size;\n    int x, y;\n    int size = 1 << log2_size;\n\n    if (shift > 0) {\n        int offset = 1 << (shift - 1);\n        for (y = 0; y < size; y++) {\n            for (x = 0; x < size; x++) {\n                *coeffs = (*coeffs + offset) >> shift;\n                coeffs++;\n            }\n        }\n    } else {\n        for (y = 0; y < size; y++) {\n            for (x = 0; x < size; x++) {\n                *coeffs = *coeffs << -shift;\n                coeffs++;\n            }\n        }\n    }\n}\n\n#define SET(dst, x)   (dst) = (x)\n#define SCALE(dst, x) (dst) = av_clip_int16(((x) + add) >> shift)\n\n#define TR_4x4_LUMA(dst, src, step, assign)                             \\\n    do {                                                                \\\n        int c0 = src[0 * step] + src[2 * step];                         \\\n        int c1 = src[2 * step] + src[3 * step];                         \\\n        int c2 = src[0 * step] - src[3 * step];                         \\\n        int c3 = 74 * src[1 * step];                                    \\\n                                                                        \\\n        assign(dst[2 * step], 74 * (src[0 * step] -                     \\\n                                    src[2 * step] +                     \\\n                                    src[3 * step]));                    \\\n        assign(dst[0 * step], 29 * c0 + 55 * c1 + c3);                  \\\n        assign(dst[1 * step], 55 * c2 - 29 * c1 + c3);                  \\\n        assign(dst[3 * step], 55 * c0 + 29 * c2 - c3);                  \\\n    } while (0)\n\nstatic void FUNC(transform_4x4_luma)(int16_t *coeffs)\n{\n    int i;\n    int shift    = 7;\n    int add      = 1 << (shift - 1);\n    int16_t *src = coeffs;\n\n    for (i = 0; i < 4; i++) {\n        TR_4x4_LUMA(src, src, 4, SCALE);\n        src++;\n    }\n\n    shift = 20 - BIT_DEPTH;\n    add   = 1 << (shift - 1);\n    for (i = 0; i < 4; i++) {\n        TR_4x4_LUMA(coeffs, coeffs, 1, SCALE);\n        coeffs += 4;\n    }\n}\n\n#undef TR_4x4_LUMA\n\n#define TR_4(dst, src, dstep, sstep, assign, end)                 \\\n    do {                                                          \\\n        const int e0 = 64 * src[0 * sstep] + 64 * src[2 * sstep]; \\\n        const int e1 = 64 * src[0 * sstep] - 64 * src[2 * sstep]; \\\n        const int o0 = 83 * src[1 * sstep] + 36 * src[3 * sstep]; \\\n        const int o1 = 36 * src[1 * sstep] - 83 * src[3 * sstep]; \\\n                                                                  \\\n        assign(dst[0 * dstep], e0 + o0);                          \\\n        assign(dst[1 * dstep], e1 + o1);                          \\\n        assign(dst[2 * dstep], e1 - o1);                          \\\n        assign(dst[3 * dstep], e0 - o0);                          \\\n    } while (0)\n\n#define TR_8(dst, src, dstep, sstep, assign, end)                 \\\n    do {                                                          \\\n        int i, j;                                                 \\\n        int e_8[4];                                               \\\n        int o_8[4] = { 0 };                                       \\\n        for (j = 1; j < end; j += 2)                              \\\n            for (i = 0; i < 4; i++)                               \\\n                o_8[i] += transform[4 * j][i] * src[j * sstep];   \\\n        TR_4(e_8, src, 1, 2 * sstep, SET, 4);                     \\\n                                                                  \\\n        for (i = 0; i < 4; i++) {                                 \\\n            assign(dst[i * dstep], e_8[i] + o_8[i]);              \\\n            assign(dst[(7 - i) * dstep], e_8[i] - o_8[i]);        \\\n        }                                                         \\\n    } while (0)\n\n#ifdef _MSC_VER\n\n#define TR_16(dst, src, dstep, sstep, assign, end)                  \\\n    do {                                                            \\\n        int i, j;                                                   \\\n        int e_16[8];                                                \\\n        int o_16[8];                                                \\\n        __m128i o_0, o_1;                                           \\\n        o_0 =  o_1 = _mm_setzero_si128();                           \\\n        for (j = 1; j < end; j += 2) {                              \\\n            __m128i vhi, vlo;                                       \\\n            const short multiplier = src[j * sstep];                \\\n            __m128i coeffs = _mm_set1_epi16(multiplier);            \\\n            __m128i buf = _mm_castpd_si128(_mm_load_sd((const double*) transform[2 * j])); \\\n            buf = _mm_srai_epi16(_mm_unpacklo_epi8(buf, buf), 8);   \\\n            vhi = _mm_mulhi_epi16(buf, coeffs);                     \\\n            vlo = _mm_mullo_epi16(buf, coeffs);                     \\\n            o_0 = _mm_add_epi32(o_0, _mm_unpacklo_epi16(vlo, vhi)); \\\n            o_1 = _mm_add_epi32(o_1, _mm_unpackhi_epi16(vlo, vhi)); \\\n        }                                                           \\\n        ((__m128i*) o_16)[0] = o_0;                                 \\\n        ((__m128i*) o_16)[1] = o_1;                                 \\\n        TR_8(e_16, src, 1, 2 * sstep, SET, 8);                      \\\n                                                                    \\\n        for (i = 0; i < 8; i++) {                                   \\\n            assign(dst[i * dstep], e_16[i] + o_16[i]);              \\\n            assign(dst[(15 - i) * dstep], e_16[i] - o_16[i]);       \\\n        }                                                           \\\n    } while (0)\n\n\n#define TR_32(dst, src, dstep, sstep, assign, end)                  \\\n    do {                                                            \\\n        int i, j;                                                   \\\n        int e_32[16];                                               \\\n        int o_32[16];                                               \\\n        __m128i o_0, o_1, o_2, o_3;                                 \\\n        o_0 =  o_1 =  o_2 = o_3 = _mm_setzero_si128();              \\\n        for (j = 1; j < end; j += 2) {                              \\\n            __m128i vhi, vlo;                                       \\\n            const short multiplier = src[j * sstep];                \\\n            __m128i coeffs = _mm_set1_epi16(multiplier);            \\\n            __m128i buf = _mm_castpd_si128(_mm_load_sd((const double*) transform[j])); \\\n            buf = _mm_srai_epi16(_mm_unpacklo_epi8(buf, buf), 8);   \\\n            vhi = _mm_mulhi_epi16(buf, coeffs);                     \\\n            vlo = _mm_mullo_epi16(buf, coeffs);                     \\\n            o_0 = _mm_add_epi32(o_0, _mm_unpacklo_epi16(vlo, vhi)); \\\n            o_1 = _mm_add_epi32(o_1, _mm_unpackhi_epi16(vlo, vhi)); \\\n            buf = _mm_castpd_si128(_mm_load_sd((const double*) &transform[j][8])); \\\n            buf = _mm_srai_epi16(_mm_unpacklo_epi8(buf, buf), 8);   \\\n            vhi = _mm_mulhi_epi16(buf, coeffs);                     \\\n            vlo = _mm_mullo_epi16(buf, coeffs);                     \\\n            o_2 = _mm_add_epi32(o_2, _mm_unpacklo_epi16(vlo, vhi)); \\\n            o_3 = _mm_add_epi32(o_3, _mm_unpackhi_epi16(vlo, vhi)); \\\n        }                                                           \\\n        ((__m128i*) o_32)[0] = o_0;                                 \\\n        ((__m128i*) o_32)[1] = o_1;                                 \\\n        ((__m128i*) o_32)[2] = o_2;                                 \\\n        ((__m128i*) o_32)[3] = o_3;                                 \\\n        TR_16(e_32, src, 1, 2 * sstep, SET, end / 2);               \\\n                                                                    \\\n        for (i = 0; i < 16; i++) {                                  \\\n            assign(dst[i * dstep], e_32[i] + o_32[i]);              \\\n            assign(dst[(31 - i) * dstep], e_32[i] - o_32[i]);       \\\n        }                                                           \\\n    } while (0)\n\n#else\n\n#define TR_16(dst, src, dstep, sstep, assign, end)                \\\n    do {                                                          \\\n        int i, j;                                                 \\\n        int e_16[8];                                              \\\n        int o_16[8] = { 0 };                                      \\\n        for (j = 1; j < end; j += 2)                              \\\n            for (i = 0; i < 8; i++)                               \\\n                o_16[i] += transform[2 * j][i] * src[j * sstep];  \\\n        TR_8(e_16, src, 1, 2 * sstep, SET, 8);                    \\\n                                                                  \\\n        for (i = 0; i < 8; i++) {                                 \\\n            assign(dst[i * dstep], e_16[i] + o_16[i]);            \\\n            assign(dst[(15 - i) * dstep], e_16[i] - o_16[i]);     \\\n        }                                                         \\\n    } while (0)\n\n#define TR_32(dst, src, dstep, sstep, assign, end)                \\\n    do {                                                          \\\n        int i, j;                                                 \\\n        int e_32[16];                                             \\\n        int o_32[16] = { 0 };                                     \\\n        for (j = 1; j < end; j += 2)                              \\\n            for (i = 0; i < 16; i++)                              \\\n                o_32[i] += transform[j][i] * src[j * sstep];      \\\n        TR_16(e_32, src, 1, 2 * sstep, SET, end / 2);             \\\n                                                                  \\\n        for (i = 0; i < 16; i++) {                                \\\n            assign(dst[i * dstep], e_32[i] + o_32[i]);            \\\n            assign(dst[(31 - i) * dstep], e_32[i] - o_32[i]);     \\\n        }                                                         \\\n    } while (0)\n\n#endif\n\n#define IDCT_VAR4(H)                                              \\\n    int limit2 = FFMIN(col_limit + 4, H)\n#define IDCT_VAR8(H)                                              \\\n    int limit  = FFMIN(col_limit, H);                             \\\n    int limit2 = FFMIN(col_limit + 4, H)\n#define IDCT_VAR16(H)   IDCT_VAR8(H)\n#define IDCT_VAR32(H)   IDCT_VAR8(H)\n\n#define IDCT(H)                                                   \\\nstatic void FUNC(idct_ ## H ## x ## H )(int16_t *coeffs,          \\\n                                        int col_limit)            \\\n{                                                                 \\\n    int i;                                                        \\\n    int      shift = 7;                                           \\\n    int      add   = 1 << (shift - 1);                            \\\n    int16_t *src   = coeffs;                                      \\\n    IDCT_VAR ## H(H);                                             \\\n                                                                  \\\n    for (i = 0; i < H; i++) {                                     \\\n        TR_ ## H(src, src, H, H, SCALE, limit2);                  \\\n        if (limit2 < H && i%4 == 0 && !!i)                        \\\n            limit2 -= 4;                                          \\\n        src++;                                                    \\\n    }                                                             \\\n                                                                  \\\n    shift = 20 - BIT_DEPTH;                                       \\\n    add   = 1 << (shift - 1);                                     \\\n    for (i = 0; i < H; i++) {                                     \\\n        TR_ ## H(coeffs, coeffs, 1, 1, SCALE, limit);             \\\n        coeffs += H;                                              \\\n    }                                                             \\\n}\n\n#define IDCT_DC(H)                                                \\\nstatic void FUNC(idct_ ## H ## x ## H ## _dc)(int16_t *coeffs)    \\\n{                                                                 \\\n    int i, j;                                                     \\\n    int shift = 14 - BIT_DEPTH;                                   \\\n    int add   = 1 << (shift - 1);                                 \\\n    int coeff = (((coeffs[0] + 1) >> 1) + add) >> shift;          \\\n                                                                  \\\n    for (j = 0; j < H; j++) {                                     \\\n        for (i = 0; i < H; i++) {                                 \\\n            coeffs[i + j * H] = coeff;                            \\\n        }                                                         \\\n    }                                                             \\\n}\n\nIDCT( 4)\nIDCT( 8)\nIDCT(16)\nIDCT(32)\n\nIDCT_DC( 4)\nIDCT_DC( 8)\nIDCT_DC(16)\nIDCT_DC(32)\n\n#undef TR_4\n#undef TR_8\n#undef TR_16\n#undef TR_32\n\n#undef SET\n#undef SCALE\n\nstatic void FUNC(sao_band_filter)(uint8_t *_dst, uint8_t *_src,\n                                  ptrdiff_t stride_dst, ptrdiff_t stride_src,\n                                  int16_t *sao_offset_val, int sao_left_class,\n                                  int width, int height)\n{\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int offset_table[32] = { 0 };\n    int k, y, x;\n    int shift  = BIT_DEPTH - 5;\n\n    stride_dst /= sizeof(pixel);\n    stride_src /= sizeof(pixel);\n\n    for (k = 0; k < 4; k++)\n        offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1];\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(src[x] + offset_table[src[x] >> shift]);\n        dst += stride_dst;\n        src += stride_src;\n    }\n}\n\n#define CMP(a, b) (((a) > (b)) - ((a) < (b)))\n\nstatic void FUNC(sao_edge_filter)(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val,\n                                  int eo, int width, int height) {\n\n    static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 };\n    static const int8_t pos[4][2][2] = {\n        { { -1,  0 }, {  1, 0 } }, // horizontal\n        { {  0, -1 }, {  0, 1 } }, // vertical\n        { { -1, -1 }, {  1, 1 } }, // 45 degree\n        { {  1, -1 }, { -1, 1 } }, // 135 degree\n    };\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int a_stride, b_stride;\n    int x, y;\n    ptrdiff_t stride_src = (2*MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE) / sizeof(pixel);\n    stride_dst /= sizeof(pixel);\n\n    a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src;\n    b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src;\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            int diff0 = CMP(src[x], src[x + a_stride]);\n            int diff1 = CMP(src[x], src[x + b_stride]);\n            int offset_val        = edge_idx[2 + diff0 + diff1];\n            dst[x] = av_clip_pixel(src[x] + sao_offset_val[offset_val]);\n        }\n        src += stride_src;\n        dst += stride_dst;\n    }\n}\n\nstatic void FUNC(sao_edge_restore_0)(uint8_t *_dst, uint8_t *_src,\n                                    ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao,\n                                    int *borders, int _width, int _height,\n                                    int c_idx, uint8_t *vert_edge,\n                                    uint8_t *horiz_edge, uint8_t *diag_edge)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int16_t *sao_offset_val = sao->offset_val[c_idx];\n    int sao_eo_class    = sao->eo_class[c_idx];\n    int init_x = 0, width = _width, height = _height;\n\n    stride_dst /= sizeof(pixel);\n    stride_src /= sizeof(pixel);\n\n    if (sao_eo_class != SAO_EO_VERT) {\n        if (borders[0]) {\n            int offset_val = sao_offset_val[0];\n            for (y = 0; y < height; y++) {\n                dst[y * stride_dst] = av_clip_pixel(src[y * stride_src] + offset_val);\n            }\n            init_x = 1;\n        }\n        if (borders[2]) {\n            int offset_val = sao_offset_val[0];\n            int offset     = width - 1;\n            for (x = 0; x < height; x++) {\n                dst[x * stride_dst + offset] = av_clip_pixel(src[x * stride_src + offset] + offset_val);\n            }\n            width--;\n        }\n    }\n    if (sao_eo_class != SAO_EO_HORIZ) {\n        if (borders[1]) {\n            int offset_val = sao_offset_val[0];\n            for (x = init_x; x < width; x++)\n                dst[x] = av_clip_pixel(src[x] + offset_val);\n        }\n        if (borders[3]) {\n            int offset_val   = sao_offset_val[0];\n            ptrdiff_t y_stride_dst = stride_dst * (height - 1);\n            ptrdiff_t y_stride_src = stride_src * (height - 1);\n            for (x = init_x; x < width; x++)\n                dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + offset_val);\n            height--;\n        }\n    }\n}\n\nstatic void FUNC(sao_edge_restore_1)(uint8_t *_dst, uint8_t *_src,\n                                    ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao,\n                                    int *borders, int _width, int _height,\n                                    int c_idx, uint8_t *vert_edge,\n                                    uint8_t *horiz_edge, uint8_t *diag_edge)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int16_t *sao_offset_val = sao->offset_val[c_idx];\n    int sao_eo_class    = sao->eo_class[c_idx];\n    int init_x = 0, init_y = 0, width = _width, height = _height;\n\n    stride_dst /= sizeof(pixel);\n    stride_src /= sizeof(pixel);\n\n    if (sao_eo_class != SAO_EO_VERT) {\n        if (borders[0]) {\n            int offset_val = sao_offset_val[0];\n            for (y = 0; y < height; y++) {\n                dst[y * stride_dst] = av_clip_pixel(src[y * stride_src] + offset_val);\n            }\n            init_x = 1;\n        }\n        if (borders[2]) {\n            int offset_val = sao_offset_val[0];\n            int offset     = width - 1;\n            for (x = 0; x < height; x++) {\n                dst[x * stride_dst + offset] = av_clip_pixel(src[x * stride_src + offset] + offset_val);\n            }\n            width--;\n        }\n    }\n    if (sao_eo_class != SAO_EO_HORIZ) {\n        if (borders[1]) {\n            int offset_val = sao_offset_val[0];\n            for (x = init_x; x < width; x++)\n                dst[x] = av_clip_pixel(src[x] + offset_val);\n            init_y = 1;\n        }\n        if (borders[3]) {\n            int offset_val   = sao_offset_val[0];\n            ptrdiff_t y_stride_dst = stride_dst * (height - 1);\n            ptrdiff_t y_stride_src = stride_src * (height - 1);\n            for (x = init_x; x < width; x++)\n                dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + offset_val);\n            height--;\n        }\n    }\n\n    {\n        int save_upper_left  = !diag_edge[0] && sao_eo_class == SAO_EO_135D && !borders[0] && !borders[1];\n        int save_upper_right = !diag_edge[1] && sao_eo_class == SAO_EO_45D  && !borders[1] && !borders[2];\n        int save_lower_right = !diag_edge[2] && sao_eo_class == SAO_EO_135D && !borders[2] && !borders[3];\n        int save_lower_left  = !diag_edge[3] && sao_eo_class == SAO_EO_45D  && !borders[0] && !borders[3];\n\n        // Restore pixels that can't be modified\n        if(vert_edge[0] && sao_eo_class != SAO_EO_VERT) {\n            for(y = init_y+save_upper_left; y< height-save_lower_left; y++)\n                dst[y*stride_dst] = src[y*stride_src];\n        }\n        if(vert_edge[1] && sao_eo_class != SAO_EO_VERT) {\n            for(y = init_y+save_upper_right; y< height-save_lower_right; y++)\n                dst[y*stride_dst+width-1] = src[y*stride_src+width-1];\n        }\n\n        if(horiz_edge[0] && sao_eo_class != SAO_EO_HORIZ) {\n            for(x = init_x+save_upper_left; x < width-save_upper_right; x++)\n                dst[x] = src[x];\n        }\n        if(horiz_edge[1] && sao_eo_class != SAO_EO_HORIZ) {\n            for(x = init_x+save_lower_left; x < width-save_lower_right; x++)\n                dst[(height-1)*stride_dst+x] = src[(height-1)*stride_src+x];\n        }\n        if(diag_edge[0] && sao_eo_class == SAO_EO_135D)\n            dst[0] = src[0];\n        if(diag_edge[1] && sao_eo_class == SAO_EO_45D)\n            dst[width-1] = src[width-1];\n        if(diag_edge[2] && sao_eo_class == SAO_EO_135D)\n            dst[stride_dst*(height-1)+width-1] = src[stride_src*(height-1)+width-1];\n        if(diag_edge[3] && sao_eo_class == SAO_EO_45D)\n            dst[stride_dst*(height-1)] = src[stride_src*(height-1)];\n\n    }\n}\n\n#undef CMP\n\n////////////////////////////////////////////////////////////////////////////////\n//\n////////////////////////////////////////////////////////////////////////////////\nstatic void FUNC(put_hevc_pel_pixels)(int16_t *dst,\n                                      uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = src[x] << (14 - BIT_DEPTH);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_uni_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                          int height, intptr_t mx, intptr_t my, int width)\n{\n    int y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    for (y = 0; y < height; y++) {\n        memcpy(dst, src, width * sizeof(pixel));\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_bi_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                         int16_t *src2,\n                                         int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14  + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((src[x] << (14 - BIT_DEPTH)) + src2[x] + offset) >> shift);\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_uni_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                            int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((src[x] << (14 - BIT_DEPTH)) * wx + offset) >> shift) + ox);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_bi_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                           int16_t *src2,\n                                           int height, int denom, int wx0, int wx1,\n                                           int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14  + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift;\n\n    int bias = ((ox0 + ox1) * (1 << (BIT_DEPTH - 8)) + 1) << (log2Wd - 1);\n    wx1 <<= (14 - BIT_DEPTH);\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel(( src[x] * wx1 + src2[x] * wx0 + bias) >> log2Wd);\n        }\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//\n////////////////////////////////////////////////////////////////////////////////\n\n#define QPEL_FILTER_0(src, stride) \\\n    (-1 * src[x - 3 * stride] +    \\\n    4 * src[x - 2 * stride] +      \\\n    -10 * src[x - stride] +        \\\n    58 * src[x] +                  \\\n    17 * src[x + stride] +         \\\n    -5 * src[x + 2 * stride] +     \\\n    1 * src[x + 3 * stride])\n\n#define QPEL_FILTER_1(src, stride) \\\n    (-1 * src[x - 3 * stride] +    \\\n    4 * src[x - 2 * stride] +      \\\n    -11 * src[x - stride] +        \\\n    40 * src[x] +                  \\\n    40 * src[x + stride] +         \\\n    -11 * src[x + 2 * stride] +    \\\n    4 * src[x + 3 * stride] +      \\\n    -1 * src[x + 4 * stride])\n\n#define QPEL_FILTER_2(src, stride) \\\n    (1 * src[x - 2 * stride] +     \\\n    -5 * src[x - stride] +         \\\n    17 * src[x] +                  \\\n    58 * src[x + stride] +         \\\n    -10 * src[x + 2 * stride] +    \\\n    4 * src[x + 3 * stride] +      \\\n    -1 * src[x + 4 * stride])\n\n#define QPEL_MACRO_DISPATCH(idx, macro)           \\\n    if ((idx) < 1) { macro(QPEL_FILTER_0) }       \\\n    else if ((idx) == 1) { macro(QPEL_FILTER_1) } \\\n    else { macro(QPEL_FILTER_2) }\n\n\nstatic void FUNC(put_hevc_qpel_h)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height; y++) {                              \\\n        for (x = 0; x < width; x++)                             \\\n            dst[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                       \\\n        dst += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_v)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n\n#define QPEL_BODY(QPEL_FILTER)                                          \\\n    for (y = 0; y < height; y++)  {                                     \\\n        for (x = 0; x < width; x++)                                     \\\n            dst[x] = QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                               \\\n        dst += MAX_PB_SIZE;                                             \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_hv)(int16_t *dst,\n                                   uint8_t *_src,\n                                   ptrdiff_t _srcstride,\n                                   int height, intptr_t mx,\n                                   intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height + QPEL_EXTRA; y++) {                 \\\n        for (x = 0; x < width; x++)                             \\\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                       \\\n        tmp += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height; y++) {                              \\\n        for (x = 0; x < width; x++)                             \\\n            dst[x] = QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6;        \\\n        tmp += MAX_PB_SIZE;                                     \\\n        dst += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_uni_h)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                      uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = 14 - BIT_DEPTH;\n\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n#define QPEL_BODY(QPEL_FILTER)                                                                      \\\n    for (y = 0; y < height; y++) {                                                                  \\\n        for (x = 0; x < width; x++)                                                                 \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + offset) >> shift);   \\\n        src += srcstride;                                                                           \\\n        dst += dststride;                                                                           \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14  + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n#define QPEL_BODY(QPEL_FILTER)                                                                              \\\n    for (y = 0; y < height; y++) {                                                                          \\\n        for (x = 0; x < width; x++)                                                                         \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift); \\\n        src  += srcstride;                                                                                  \\\n        dst  += dststride;                                                                                  \\\n        src2 += MAX_PB_SIZE;                                                                                \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_uni_v)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                     uint8_t *_src, ptrdiff_t _srcstride,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = 14 - BIT_DEPTH;\n\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n#define QPEL_BODY(QPEL_FILTER)                                                                              \\\n    for (y = 0; y < height; y++) {                                                                          \\\n        for (x = 0; x < width; x++)                                                                         \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + offset) >> shift);   \\\n        src += srcstride;                                                                                   \\\n        dst += dststride;                                                                                   \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\n\nstatic void FUNC(put_hevc_qpel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n#define QPEL_BODY(QPEL_FILTER)                                                                                      \\\n    for (y = 0; y < height; y++) {                                                                                  \\\n        for (x = 0; x < width; x++)                                                                                 \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift); \\\n        src  += srcstride;                                                                                          \\\n        dst  += dststride;                                                                                          \\\n        src2 += MAX_PB_SIZE;                                                                                        \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_uni_hv)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                       uint8_t *_src, ptrdiff_t _srcstride,\n                                       int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift =  14 - BIT_DEPTH;\n\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height + QPEL_EXTRA; y++) {                 \\\n        for (x = 0; x < width; x++)                             \\\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                       \\\n        tmp += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n\n#define QPEL_BODY(QPEL_FILTER)                                                                  \\\n    for (y = 0; y < height; y++) {                                                              \\\n        for (x = 0; x < width; x++)                                                             \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + offset) >> shift);   \\\n        tmp += MAX_PB_SIZE;                                                                     \\\n        dst += dststride;                                                                       \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int16_t *src2,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height + QPEL_EXTRA; y++) {                 \\\n        for (x = 0; x < width; x++)                             \\\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                       \\\n        tmp += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n\n#define QPEL_BODY(QPEL_FILTER)                                                                          \\\n    for (y = 0; y < height; y++) {                                                                      \\\n        for (x = 0; x < width; x++)                                                                     \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift); \\\n        tmp  += MAX_PB_SIZE;                                                                            \\\n        dst  += dststride;                                                                              \\\n        src2 += MAX_PB_SIZE;                                                                            \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_uni_w_h)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                        uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox,\n                                        intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox = ox * (1 << (BIT_DEPTH - 8));\n#define QPEL_BODY(QPEL_FILTER)                                                                                  \\\n    for (y = 0; y < height; y++) {                                                                              \\\n        for (x = 0; x < width; x++)                                                                             \\\n            dst[x] = av_clip_pixel((((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);   \\\n        src += srcstride;                                                                                       \\\n        dst += dststride;                                                                                       \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14  + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n#define QPEL_BODY(QPEL_FILTER)                                                                          \\\n    for (y = 0; y < height; y++) {                                                                      \\\n        for (x = 0; x < width; x++)                                                                     \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +    \\\n                                    ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));                      \\\n        src  += srcstride;                                                                              \\\n        dst  += dststride;                                                                              \\\n        src2 += MAX_PB_SIZE;                                                                            \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_uni_w_v)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                        uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox,\n                                        intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox = ox * (1 << (BIT_DEPTH - 8));\n#define QPEL_BODY(QPEL_FILTER)                                                                                          \\\n    for (y = 0; y < height; y++) {                                                                                      \\\n        for (x = 0; x < width; x++)                                                                                     \\\n            dst[x] = av_clip_pixel((((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);   \\\n        src += srcstride;                                                                                               \\\n        dst += dststride;                                                                                               \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n#define QPEL_BODY(QPEL_FILTER)                                                                                  \\\n    for (y = 0; y < height; y++) {                                                                              \\\n        for (x = 0; x < width; x++)                                                                             \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +    \\\n                                    ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));                              \\\n        src  += srcstride;                                                                                      \\\n        dst  += dststride;                                                                                      \\\n        src2 += MAX_PB_SIZE;                                                                                    \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_uni_w_hv)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                         uint8_t *_src, ptrdiff_t _srcstride,\n                                         int height, int denom, int wx, int ox,\n                                         intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height + QPEL_EXTRA; y++) {                 \\\n        for (x = 0; x < width; x++)                             \\\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                       \\\n        tmp += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n\n    ox = ox * (1 << (BIT_DEPTH - 8));\n\n#define QPEL_BODY(QPEL_FILTER)                                                                              \\\n    for (y = 0; y < height; y++) {                                                                          \\\n        for (x = 0; x < width; x++)                                                                         \\\n            dst[x] = av_clip_pixel((((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx + offset) >> shift) + ox);   \\\n        tmp += MAX_PB_SIZE;                                                                                 \\\n        dst += dststride;                                                                                   \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int16_t *src2,\n                                        int height, int denom, int wx0, int wx1,\n                                        int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height + QPEL_EXTRA; y++) {                 \\\n        for (x = 0; x < width; x++)                             \\\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                       \\\n        tmp += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n#define QPEL_BODY(QPEL_FILTER)                                                                      \\\n    for (y = 0; y < height; y++) {                                                                  \\\n        for (x = 0; x < width; x++)                                                                 \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 +    \\\n                                    ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));                  \\\n        tmp  += MAX_PB_SIZE;                                                                        \\\n        dst  += dststride;                                                                          \\\n        src2 += MAX_PB_SIZE;                                                                        \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//\n////////////////////////////////////////////////////////////////////////////////\n#define EPEL_FILTER(src, stride)                                               \\\n    (filter[0] * src[x - stride] +                                             \\\n     filter[1] * src[x]          +                                             \\\n     filter[2] * src[x + stride] +                                             \\\n     filter[3] * src[x + 2 * stride])\n\nstatic void FUNC(put_hevc_epel_h)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_v)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_hv)(int16_t *dst,\n                                   uint8_t *_src, ptrdiff_t _srcstride,\n                                   int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6;\n        tmp += MAX_PB_SIZE;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + offset) >> shift);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);\n        }\n        dst  += dststride;\n        src  += srcstride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    int shift = 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + offset) >> shift);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);\n        dst  += dststride;\n        src  += srcstride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + offset) >> shift);\n        tmp += MAX_PB_SIZE;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int16_t *src2,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift);\n        tmp  += MAX_PB_SIZE;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel((((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);\n        }\n        dst += dststride;\n        src += srcstride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel((((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);\n        }\n        dst += dststride;\n        src += srcstride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                         int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx + offset) >> shift) + ox);\n        tmp += MAX_PB_SIZE;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int16_t *src2,\n                                        int height, int denom, int wx0, int wx1,\n                                        int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1));\n        tmp  += MAX_PB_SIZE;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\n// line zero\n#define P3 pix[-4 * xstride]\n#define P2 pix[-3 * xstride]\n#define P1 pix[-2 * xstride]\n#define P0 pix[-1 * xstride]\n#define Q0 pix[0 * xstride]\n#define Q1 pix[1 * xstride]\n#define Q2 pix[2 * xstride]\n#define Q3 pix[3 * xstride]\n\n// line three. used only for deblocking decision\n#define TP3 pix[-4 * xstride + 3 * ystride]\n#define TP2 pix[-3 * xstride + 3 * ystride]\n#define TP1 pix[-2 * xstride + 3 * ystride]\n#define TP0 pix[-1 * xstride + 3 * ystride]\n#define TQ0 pix[0  * xstride + 3 * ystride]\n#define TQ1 pix[1  * xstride + 3 * ystride]\n#define TQ2 pix[2  * xstride + 3 * ystride]\n#define TQ3 pix[3  * xstride + 3 * ystride]\n\nstatic void FUNC(hevc_loop_filter_luma)(uint8_t *_pix,\n                                        ptrdiff_t _xstride, ptrdiff_t _ystride,\n                                        int beta, int *_tc,\n                                        uint8_t *_no_p, uint8_t *_no_q)\n{\n    int d, j;\n    pixel *pix        = (pixel *)_pix;\n    ptrdiff_t xstride = _xstride / sizeof(pixel);\n    ptrdiff_t ystride = _ystride / sizeof(pixel);\n\n    beta <<= BIT_DEPTH - 8;\n\n    for (j = 0; j < 2; j++) {\n        const int dp0  = abs(P2  - 2 * P1  + P0);\n        const int dq0  = abs(Q2  - 2 * Q1  + Q0);\n        const int dp3  = abs(TP2 - 2 * TP1 + TP0);\n        const int dq3  = abs(TQ2 - 2 * TQ1 + TQ0);\n        const int d0   = dp0 + dq0;\n        const int d3   = dp3 + dq3;\n        const int tc   = _tc[j]   << (BIT_DEPTH - 8);\n        const int no_p = _no_p[j];\n        const int no_q = _no_q[j];\n\n        if (d0 + d3 >= beta) {\n            pix += 4 * ystride;\n            continue;\n        } else {\n            const int beta_3 = beta >> 3;\n            const int beta_2 = beta >> 2;\n            const int tc25   = ((tc * 5 + 1) >> 1);\n\n            if (abs(P3  -  P0) + abs(Q3  -  Q0) < beta_3 && abs(P0  -  Q0) < tc25 &&\n                abs(TP3 - TP0) + abs(TQ3 - TQ0) < beta_3 && abs(TP0 - TQ0) < tc25 &&\n                                      (d0 << 1) < beta_2 &&      (d3 << 1) < beta_2) {\n                // strong filtering\n                const int tc2 = tc << 1;\n                for (d = 0; d < 4; d++) {\n                    const int p3 = P3;\n                    const int p2 = P2;\n                    const int p1 = P1;\n                    const int p0 = P0;\n                    const int q0 = Q0;\n                    const int q1 = Q1;\n                    const int q2 = Q2;\n                    const int q3 = Q3;\n                    if (!no_p) {\n                        P0 = p0 + av_clip(((p2 + 2 * p1 + 2 * p0 + 2 * q0 + q1 + 4) >> 3) - p0, -tc2, tc2);\n                        P1 = p1 + av_clip(((p2 + p1 + p0 + q0 + 2) >> 2) - p1, -tc2, tc2);\n                        P2 = p2 + av_clip(((2 * p3 + 3 * p2 + p1 + p0 + q0 + 4) >> 3) - p2, -tc2, tc2);\n                    }\n                    if (!no_q) {\n                        Q0 = q0 + av_clip(((p1 + 2 * p0 + 2 * q0 + 2 * q1 + q2 + 4) >> 3) - q0, -tc2, tc2);\n                        Q1 = q1 + av_clip(((p0 + q0 + q1 + q2 + 2) >> 2) - q1, -tc2, tc2);\n                        Q2 = q2 + av_clip(((2 * q3 + 3 * q2 + q1 + q0 + p0 + 4) >> 3) - q2, -tc2, tc2);\n                    }\n                    pix += ystride;\n                }\n            } else { // normal filtering\n                int nd_p = 1;\n                int nd_q = 1;\n                const int tc_2 = tc >> 1;\n                if (dp0 + dp3 < ((beta + (beta >> 1)) >> 3))\n                    nd_p = 2;\n                if (dq0 + dq3 < ((beta + (beta >> 1)) >> 3))\n                    nd_q = 2;\n\n                for (d = 0; d < 4; d++) {\n                    const int p2 = P2;\n                    const int p1 = P1;\n                    const int p0 = P0;\n                    const int q0 = Q0;\n                    const int q1 = Q1;\n                    const int q2 = Q2;\n                    int delta0   = (9 * (q0 - p0) - 3 * (q1 - p1) + 8) >> 4;\n                    if (abs(delta0) < 10 * tc) {\n                        delta0 = av_clip(delta0, -tc, tc);\n                        if (!no_p)\n                            P0 = av_clip_pixel(p0 + delta0);\n                        if (!no_q)\n                            Q0 = av_clip_pixel(q0 - delta0);\n                        if (!no_p && nd_p > 1) {\n                            const int deltap1 = av_clip((((p2 + p0 + 1) >> 1) - p1 + delta0) >> 1, -tc_2, tc_2);\n                            P1 = av_clip_pixel(p1 + deltap1);\n                        }\n                        if (!no_q && nd_q > 1) {\n                            const int deltaq1 = av_clip((((q2 + q0 + 1) >> 1) - q1 - delta0) >> 1, -tc_2, tc_2);\n                            Q1 = av_clip_pixel(q1 + deltaq1);\n                        }\n                    }\n                    pix += ystride;\n                }\n            }\n        }\n    }\n}\n\nstatic void FUNC(hevc_loop_filter_chroma)(uint8_t *_pix, ptrdiff_t _xstride,\n                                          ptrdiff_t _ystride, int *_tc,\n                                          uint8_t *_no_p, uint8_t *_no_q)\n{\n    int d, j, no_p, no_q;\n    pixel *pix        = (pixel *)_pix;\n    ptrdiff_t xstride = _xstride / sizeof(pixel);\n    ptrdiff_t ystride = _ystride / sizeof(pixel);\n\n    for (j = 0; j < 2; j++) {\n        const int tc = _tc[j] << (BIT_DEPTH - 8);\n        if (tc <= 0) {\n            pix += 4 * ystride;\n            continue;\n        }\n        no_p = _no_p[j];\n        no_q = _no_q[j];\n\n        for (d = 0; d < 4; d++) {\n            int delta0;\n            const int p1 = P1;\n            const int p0 = P0;\n            const int q0 = Q0;\n            const int q1 = Q1;\n            delta0 = av_clip((((q0 - p0) * 4) + p1 - q1 + 4) >> 3, -tc, tc);\n            if (!no_p)\n                P0 = av_clip_pixel(p0 + delta0);\n            if (!no_q)\n                Q0 = av_clip_pixel(q0 - delta0);\n            pix += ystride;\n        }\n    }\n}\n\nstatic void FUNC(hevc_h_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,\n                                            int32_t *tc, uint8_t *no_p,\n                                            uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_chroma)(pix, stride, sizeof(pixel), tc, no_p, no_q);\n}\n\nstatic void FUNC(hevc_v_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,\n                                            int32_t *tc, uint8_t *no_p,\n                                            uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_chroma)(pix, sizeof(pixel), stride, tc, no_p, no_q);\n}\n\nstatic void FUNC(hevc_h_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,\n                                          int beta, int32_t *tc, uint8_t *no_p,\n                                          uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_luma)(pix, stride, sizeof(pixel),\n                                beta, tc, no_p, no_q);\n}\n\nstatic void FUNC(hevc_v_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,\n                                          int beta, int32_t *tc, uint8_t *no_p,\n                                          uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_luma)(pix, sizeof(pixel), stride,\n                                beta, tc, no_p, no_q);\n}\n\n#undef P3\n#undef P2\n#undef P1\n#undef P0\n#undef Q0\n#undef Q1\n#undef Q2\n#undef Q3\n\n#undef TP3\n#undef TP2\n#undef TP1\n#undef TP0\n#undef TQ0\n#undef TQ1\n#undef TQ2\n#undef TQ3\n"
  },
  {
    "path": "ffmpeg-4.3.2-experimental-patch/common.before.h",
    "content": "/*\n * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/**\n * @file\n * common internal and external API header\n */\n\n#ifndef AVUTIL_COMMON_H\n#define AVUTIL_COMMON_H\n\n#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) && !defined(UINT64_C)\n#error missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS\n#endif\n\n#include <errno.h>\n#include <inttypes.h>\n#include <limits.h>\n#include <math.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"attributes.h\"\n#include \"macros.h\"\n#include \"version.h\"\n#include \"libavutil/avconfig.h\"\n\n#if AV_HAVE_BIGENDIAN\n#   define AV_NE(be, le) (be)\n#else\n#   define AV_NE(be, le) (le)\n#endif\n\n//rounded division & shift\n#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b))\n/* assume b>0 */\n#define ROUNDED_DIV(a,b) (((a)>=0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))\n/* Fast a/(1<<b) rounded toward +inf. Assume a>=0 and b>=0 */\n#define AV_CEIL_RSHIFT(a,b) (!av_builtin_constant_p(b) ? -((-(a)) >> (b)) \\\n                                                       : ((a) + (1<<(b)) - 1) >> (b))\n/* Backwards compat. */\n#define FF_CEIL_RSHIFT AV_CEIL_RSHIFT\n\n#define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b))\n#define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b))\n\n/**\n * Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they\n * are not representable as absolute values of their type. This is the same\n * as with *abs()\n * @see FFNABS()\n */\n#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))\n#define FFSIGN(a) ((a) > 0 ? 1 : -1)\n\n/**\n * Negative Absolute value.\n * this works for all integers of all types.\n * As with many macros, this evaluates its argument twice, it thus must not have\n * a sideeffect, that is FFNABS(x++) has undefined behavior.\n */\n#define FFNABS(a) ((a) <= 0 ? (a) : (-(a)))\n\n/**\n * Comparator.\n * For two numerical expressions x and y, gives 1 if x > y, -1 if x < y, and 0\n * if x == y. This is useful for instance in a qsort comparator callback.\n * Furthermore, compilers are able to optimize this to branchless code, and\n * there is no risk of overflow with signed types.\n * As with many macros, this evaluates its argument multiple times, it thus\n * must not have a side-effect.\n */\n#define FFDIFFSIGN(x,y) (((x)>(y)) - ((x)<(y)))\n\n#define FFMAX(a,b) ((a) > (b) ? (a) : (b))\n#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c)\n#define FFMIN(a,b) ((a) > (b) ? (b) : (a))\n#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c)\n\n#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)\n#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))\n\n/* misc math functions */\n\n#ifdef HAVE_AV_CONFIG_H\n#   include \"config.h\"\n#   include \"intmath.h\"\n#endif\n\n/* Pull in unguarded fallback defines at the end of this file. */\n#include \"common.h\"\n\n#ifndef av_log2\nav_const int av_log2(unsigned v);\n#endif\n\n#ifndef av_log2_16bit\nav_const int av_log2_16bit(unsigned v);\n#endif\n\n/**\n * Clip a signed integer value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const int av_clip_c(int a, int amin, int amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/**\n * Clip a signed 64bit integer value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/**\n * Clip a signed integer value into the 0-255 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const uint8_t av_clip_uint8_c(int a)\n{\n    if (a&(~0xFF)) return (~a)>>31;\n    else           return a;\n}\n\n/**\n * Clip a signed integer value into the -128,127 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const int8_t av_clip_int8_c(int a)\n{\n    if ((a+0x80U) & ~0xFF) return (a>>31) ^ 0x7F;\n    else                  return a;\n}\n\n/**\n * Clip a signed integer value into the 0-65535 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const uint16_t av_clip_uint16_c(int a)\n{\n    if (a&(~0xFFFF)) return (~a)>>31;\n    else             return a;\n}\n\n/**\n * Clip a signed integer value into the -32768,32767 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const int16_t av_clip_int16_c(int a)\n{\n    if ((a+0x8000U) & ~0xFFFF) return (a>>31) ^ 0x7FFF;\n    else                      return a;\n}\n\n/**\n * Clip a signed 64-bit integer value into the -2147483648,2147483647 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const int32_t av_clipl_int32_c(int64_t a)\n{\n    if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF);\n    else                                         return (int32_t)a;\n}\n\n/**\n * Clip a signed integer into the -(2^p),(2^p-1) range.\n * @param  a value to clip\n * @param  p bit position to clip at\n * @return clipped value\n */\nstatic av_always_inline av_const int av_clip_intp2_c(int a, int p)\n{\n    if (((unsigned)a + (1 << p)) & ~((2 << p) - 1))\n        return (a >> 31) ^ ((1 << p) - 1);\n    else\n        return a;\n}\n\n/**\n * Clip a signed integer to an unsigned power of two range.\n * @param  a value to clip\n * @param  p bit position to clip at\n * @return clipped value\n */\nstatic av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p)\n{\n    if (a & ~((1<<p) - 1)) return (~a) >> 31 & ((1<<p) - 1);\n    else                   return  a;\n}\n\n/**\n * Clear high bits from an unsigned integer starting with specific bit position\n * @param  a value to clip\n * @param  p bit position to clip at\n * @return clipped value\n */\nstatic av_always_inline av_const unsigned av_mod_uintp2_c(unsigned a, unsigned p)\n{\n    return a & ((1U << p) - 1);\n}\n\n/**\n * Add two signed 32-bit values with saturation.\n *\n * @param  a one value\n * @param  b another value\n * @return sum with signed saturation\n */\nstatic av_always_inline int av_sat_add32_c(int a, int b)\n{\n    return av_clipl_int32((int64_t)a + b);\n}\n\n/**\n * Add a doubled value to another value with saturation at both stages.\n *\n * @param  a first value\n * @param  b value doubled and added to a\n * @return sum sat(a + sat(2*b)) with signed saturation\n */\nstatic av_always_inline int av_sat_dadd32_c(int a, int b)\n{\n    return av_sat_add32(a, av_sat_add32(b, b));\n}\n\n/**\n * Subtract two signed 32-bit values with saturation.\n *\n * @param  a one value\n * @param  b another value\n * @return difference with signed saturation\n */\nstatic av_always_inline int av_sat_sub32_c(int a, int b)\n{\n    return av_clipl_int32((int64_t)a - b);\n}\n\n/**\n * Subtract a doubled value from another value with saturation at both stages.\n *\n * @param  a first value\n * @param  b value doubled and subtracted from a\n * @return difference sat(a - sat(2*b)) with signed saturation\n */\nstatic av_always_inline int av_sat_dsub32_c(int a, int b)\n{\n    return av_sat_sub32(a, av_sat_add32(b, b));\n}\n\n/**\n * Add two signed 64-bit values with saturation.\n *\n * @param  a one value\n * @param  b another value\n * @return sum with signed saturation\n */\nstatic av_always_inline int64_t av_sat_add64_c(int64_t a, int64_t b) {\n#if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_add_overflow)\n    int64_t tmp;\n    return !__builtin_add_overflow(a, b, &tmp) ? tmp : (tmp < 0 ? INT64_MAX : INT64_MIN);\n#else\n    if (b >= 0 && a >= INT64_MAX - b)\n        return INT64_MAX;\n    if (b <= 0 && a <= INT64_MIN - b)\n        return INT64_MIN;\n    return a + b;\n#endif\n}\n\n/**\n * Subtract two signed 64-bit values with saturation.\n *\n * @param  a one value\n * @param  b another value\n * @return difference with signed saturation\n */\nstatic av_always_inline int64_t av_sat_sub64_c(int64_t a, int64_t b) {\n#if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_sub_overflow)\n    int64_t tmp;\n    return !__builtin_sub_overflow(a, b, &tmp) ? tmp : (tmp < 0 ? INT64_MAX : INT64_MIN);\n#else\n    if (b <= 0 && a >= INT64_MAX + b)\n        return INT64_MAX;\n    if (b >= 0 && a <= INT64_MIN + b)\n        return INT64_MIN;\n    return a - b;\n#endif\n}\n\n/**\n * Clip a float value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const float av_clipf_c(float a, float amin, float amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/**\n * Clip a double value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const double av_clipd_c(double a, double amin, double amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/** Compute ceil(log2(x)).\n * @param x value used to compute ceil(log2(x))\n * @return computed ceiling of log2(x)\n */\nstatic av_always_inline av_const int av_ceil_log2_c(int x)\n{\n    return av_log2((x - 1U) << 1);\n}\n\n/**\n * Count number of bits set to one in x\n * @param x value to count bits of\n * @return the number of bits set to one in x\n */\nstatic av_always_inline av_const int av_popcount_c(uint32_t x)\n{\n    x -= (x >> 1) & 0x55555555;\n    x = (x & 0x33333333) + ((x >> 2) & 0x33333333);\n    x = (x + (x >> 4)) & 0x0F0F0F0F;\n    x += x >> 8;\n    return (x + (x >> 16)) & 0x3F;\n}\n\n/**\n * Count number of bits set to one in x\n * @param x value to count bits of\n * @return the number of bits set to one in x\n */\nstatic av_always_inline av_const int av_popcount64_c(uint64_t x)\n{\n    return av_popcount((uint32_t)x) + av_popcount((uint32_t)(x >> 32));\n}\n\nstatic av_always_inline av_const int av_parity_c(uint32_t v)\n{\n    return av_popcount(v) & 1;\n}\n\n#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))\n#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24))\n\n/**\n * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form.\n *\n * @param val      Output value, must be an lvalue of type uint32_t.\n * @param GET_BYTE Expression reading one byte from the input.\n *                 Evaluated up to 7 times (4 for the currently\n *                 assigned Unicode range).  With a memory buffer\n *                 input, this could be *ptr++, or if you want to make sure\n *                 that *ptr stops at the end of a NULL terminated string then\n *                 *ptr ? *ptr++ : 0\n * @param ERROR    Expression to be evaluated on invalid input,\n *                 typically a goto statement.\n *\n * @warning ERROR should not contain a loop control statement which\n * could interact with the internal while loop, and should force an\n * exit from the macro code (e.g. through a goto or a return) in order\n * to prevent undefined results.\n */\n#define GET_UTF8(val, GET_BYTE, ERROR)\\\n    val= (GET_BYTE);\\\n    {\\\n        uint32_t top = (val & 128) >> 1;\\\n        if ((val & 0xc0) == 0x80 || val >= 0xFE)\\\n            {ERROR}\\\n        while (val & top) {\\\n            unsigned int tmp = (GET_BYTE) - 128;\\\n            if(tmp>>6)\\\n                {ERROR}\\\n            val= (val<<6) + tmp;\\\n            top <<= 5;\\\n        }\\\n        val &= (top << 1) - 1;\\\n    }\n\n/**\n * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form.\n *\n * @param val       Output value, must be an lvalue of type uint32_t.\n * @param GET_16BIT Expression returning two bytes of UTF-16 data converted\n *                  to native byte order.  Evaluated one or two times.\n * @param ERROR     Expression to be evaluated on invalid input,\n *                  typically a goto statement.\n */\n#define GET_UTF16(val, GET_16BIT, ERROR)\\\n    val = (GET_16BIT);\\\n    {\\\n        unsigned int hi = val - 0xD800;\\\n        if (hi < 0x800) {\\\n            val = (GET_16BIT) - 0xDC00;\\\n            if (val > 0x3FFU || hi > 0x3FFU)\\\n                {ERROR}\\\n            val += (hi<<10) + 0x10000;\\\n        }\\\n    }\\\n\n/**\n * @def PUT_UTF8(val, tmp, PUT_BYTE)\n * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long).\n * @param val is an input-only argument and should be of type uint32_t. It holds\n * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If\n * val is given as a function it is executed only once.\n * @param tmp is a temporary variable and should be of type uint8_t. It\n * represents an intermediate value during conversion that is to be\n * output by PUT_BYTE.\n * @param PUT_BYTE writes the converted UTF-8 bytes to any proper destination.\n * It could be a function or a statement, and uses tmp as the input byte.\n * For example, PUT_BYTE could be \"*output++ = tmp;\" PUT_BYTE will be\n * executed up to 4 times for values in the valid UTF-8 range and up to\n * 7 times in the general case, depending on the length of the converted\n * Unicode character.\n */\n#define PUT_UTF8(val, tmp, PUT_BYTE)\\\n    {\\\n        int bytes, shift;\\\n        uint32_t in = val;\\\n        if (in < 0x80) {\\\n            tmp = in;\\\n            PUT_BYTE\\\n        } else {\\\n            bytes = (av_log2(in) + 4) / 5;\\\n            shift = (bytes - 1) * 6;\\\n            tmp = (256 - (256 >> bytes)) | (in >> shift);\\\n            PUT_BYTE\\\n            while (shift >= 6) {\\\n                shift -= 6;\\\n                tmp = 0x80 | ((in >> shift) & 0x3f);\\\n                PUT_BYTE\\\n            }\\\n        }\\\n    }\n\n/**\n * @def PUT_UTF16(val, tmp, PUT_16BIT)\n * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes).\n * @param val is an input-only argument and should be of type uint32_t. It holds\n * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If\n * val is given as a function it is executed only once.\n * @param tmp is a temporary variable and should be of type uint16_t. It\n * represents an intermediate value during conversion that is to be\n * output by PUT_16BIT.\n * @param PUT_16BIT writes the converted UTF-16 data to any proper destination\n * in desired endianness. It could be a function or a statement, and uses tmp\n * as the input byte.  For example, PUT_BYTE could be \"*output++ = tmp;\"\n * PUT_BYTE will be executed 1 or 2 times depending on input character.\n */\n#define PUT_UTF16(val, tmp, PUT_16BIT)\\\n    {\\\n        uint32_t in = val;\\\n        if (in < 0x10000) {\\\n            tmp = in;\\\n            PUT_16BIT\\\n        } else {\\\n            tmp = 0xD800 | ((in - 0x10000) >> 10);\\\n            PUT_16BIT\\\n            tmp = 0xDC00 | ((in - 0x10000) & 0x3FF);\\\n            PUT_16BIT\\\n        }\\\n    }\\\n\n\n\n#include \"mem.h\"\n\n#ifdef HAVE_AV_CONFIG_H\n#    include \"internal.h\"\n#endif /* HAVE_AV_CONFIG_H */\n\n#endif /* AVUTIL_COMMON_H */\n\n/*\n * The following definitions are outside the multiple inclusion guard\n * to ensure they are immediately available in intmath.h.\n */\n\n#ifndef av_ceil_log2\n#   define av_ceil_log2     av_ceil_log2_c\n#endif\n#ifndef av_clip\n#   define av_clip          av_clip_c\n#endif\n#ifndef av_clip64\n#   define av_clip64        av_clip64_c\n#endif\n#ifndef av_clip_uint8\n#   define av_clip_uint8    av_clip_uint8_c\n#endif\n#ifndef av_clip_int8\n#   define av_clip_int8     av_clip_int8_c\n#endif\n#ifndef av_clip_uint16\n#   define av_clip_uint16   av_clip_uint16_c\n#endif\n#ifndef av_clip_int16\n#   define av_clip_int16    av_clip_int16_c\n#endif\n#ifndef av_clipl_int32\n#   define av_clipl_int32   av_clipl_int32_c\n#endif\n#ifndef av_clip_intp2\n#   define av_clip_intp2    av_clip_intp2_c\n#endif\n#ifndef av_clip_uintp2\n#   define av_clip_uintp2   av_clip_uintp2_c\n#endif\n#ifndef av_mod_uintp2\n#   define av_mod_uintp2    av_mod_uintp2_c\n#endif\n#ifndef av_sat_add32\n#   define av_sat_add32     av_sat_add32_c\n#endif\n#ifndef av_sat_dadd32\n#   define av_sat_dadd32    av_sat_dadd32_c\n#endif\n#ifndef av_sat_sub32\n#   define av_sat_sub32     av_sat_sub32_c\n#endif\n#ifndef av_sat_dsub32\n#   define av_sat_dsub32    av_sat_dsub32_c\n#endif\n#ifndef av_sat_add64\n#   define av_sat_add64     av_sat_add64_c\n#endif\n#ifndef av_sat_sub64\n#   define av_sat_sub64     av_sat_sub64_c\n#endif\n#ifndef av_clipf\n#   define av_clipf         av_clipf_c\n#endif\n#ifndef av_clipd\n#   define av_clipd         av_clipd_c\n#endif\n#ifndef av_popcount\n#   define av_popcount      av_popcount_c\n#endif\n#ifndef av_popcount64\n#   define av_popcount64    av_popcount64_c\n#endif\n#ifndef av_parity\n#   define av_parity        av_parity_c\n#endif\n"
  },
  {
    "path": "ffmpeg-4.3.2-experimental-patch/common.h",
    "content": "/*\n * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n/**\n * @file\n * common internal and external API header\n */\n\n#ifndef AVUTIL_COMMON_H\n#define AVUTIL_COMMON_H\n\n#if defined(__cplusplus) && !defined(__STDC_CONSTANT_MACROS) && !defined(UINT64_C)\n#error missing -D__STDC_CONSTANT_MACROS / #define __STDC_CONSTANT_MACROS\n#endif\n\n#include <errno.h>\n#include <inttypes.h>\n#include <limits.h>\n#include <math.h>\n#include <stdint.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n\n#include \"attributes.h\"\n#include \"macros.h\"\n#include \"version.h\"\n#include \"libavutil/avconfig.h\"\n\n#if AV_HAVE_BIGENDIAN\n#   define AV_NE(be, le) (be)\n#else\n#   define AV_NE(be, le) (le)\n#endif\n\n//rounded division & shift\n#define RSHIFT(a,b) ((a) > 0 ? ((a) + ((1<<(b))>>1))>>(b) : ((a) + ((1<<(b))>>1)-1)>>(b))\n/* assume b>0 */\n#define ROUNDED_DIV(a,b) (((a)>=0 ? (a) + ((b)>>1) : (a) - ((b)>>1))/(b))\n/* Fast a/(1<<b) rounded toward +inf. Assume a>=0 and b>=0 */\n#define AV_CEIL_RSHIFT(a,b) (!av_builtin_constant_p(b) ? -((-(a)) >> (b)) \\\n                                                       : ((a) + (1<<(b)) - 1) >> (b))\n/* Backwards compat. */\n#define FF_CEIL_RSHIFT AV_CEIL_RSHIFT\n\n#define FFUDIV(a,b) (((a)>0 ?(a):(a)-(b)+1) / (b))\n#define FFUMOD(a,b) ((a)-(b)*FFUDIV(a,b))\n\n/**\n * Absolute value, Note, INT_MIN / INT64_MIN result in undefined behavior as they\n * are not representable as absolute values of their type. This is the same\n * as with *abs()\n * @see FFNABS()\n */\n#define FFABS(a) ((a) >= 0 ? (a) : (-(a)))\n#define FFSIGN(a) ((a) > 0 ? 1 : -1)\n\n/**\n * Negative Absolute value.\n * this works for all integers of all types.\n * As with many macros, this evaluates its argument twice, it thus must not have\n * a sideeffect, that is FFNABS(x++) has undefined behavior.\n */\n#define FFNABS(a) ((a) <= 0 ? (a) : (-(a)))\n\n/**\n * Comparator.\n * For two numerical expressions x and y, gives 1 if x > y, -1 if x < y, and 0\n * if x == y. This is useful for instance in a qsort comparator callback.\n * Furthermore, compilers are able to optimize this to branchless code, and\n * there is no risk of overflow with signed types.\n * As with many macros, this evaluates its argument multiple times, it thus\n * must not have a side-effect.\n */\n#define FFDIFFSIGN(x,y) (((x)>(y)) - ((x)<(y)))\n\n#define FFMAX(a,b) ((a) > (b) ? (a) : (b))\n#define FFMAX3(a,b,c) FFMAX(FFMAX(a,b),c)\n#define FFMIN(a,b) ((a) > (b) ? (b) : (a))\n#define FFMIN3(a,b,c) FFMIN(FFMIN(a,b),c)\n\n#define FFSWAP(type,a,b) do{type SWAP_tmp= b; b= a; a= SWAP_tmp;}while(0)\n#define FF_ARRAY_ELEMS(a) (sizeof(a) / sizeof((a)[0]))\n\n/* misc math functions */\n\n#ifdef HAVE_AV_CONFIG_H\n#   include \"config.h\"\n#   include \"intmath.h\"\n#endif\n\n/* Pull in unguarded fallback defines at the end of this file. */\n#include \"common.h\"\n\n#ifndef av_log2\nav_const int av_log2(unsigned v);\n#endif\n\n#ifndef av_log2_16bit\nav_const int av_log2_16bit(unsigned v);\n#endif\n\n/**\n * Clip a signed integer value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const int av_clip_c(int a, int amin, int amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/**\n * Clip a signed 64bit integer value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, int64_t amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/**\n * Clip a signed integer value into the 0-255 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const uint8_t av_clip_uint8_c(int a)\n{\n    if (a&(~0xFF)) return (~a)>>31;\n    else           return a;\n}\n\n/**\n * Clip a signed integer value into the -128,127 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const int8_t av_clip_int8_c(int a)\n{\n    if ((a+0x80U) & ~0xFF) return (a>>31) ^ 0x7F;\n    else                  return a;\n}\n\n/**\n * Clip a signed integer value into the 0-65535 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const uint16_t av_clip_uint16_c(int a)\n{\n    if (a&(~0xFFFF)) return (~a)>>31;\n    else             return a;\n}\n\n/**\n * Clip a signed integer value into the -32768,32767 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const int16_t av_clip_int16_c(int a)\n{\n    const int16_t noOverflowCandidate = a;\n    return (noOverflowCandidate == a) ? noOverflowCandidate : ((noOverflowCandidate < a) ? INT16_MAX : INT16_MIN);\n}\n\n/**\n * Clip a signed 64-bit integer value into the -2147483648,2147483647 range.\n * @param a value to clip\n * @return clipped value\n */\nstatic av_always_inline av_const int32_t av_clipl_int32_c(int64_t a)\n{\n    if ((a+0x80000000u) & ~UINT64_C(0xFFFFFFFF)) return (int32_t)((a>>63) ^ 0x7FFFFFFF);\n    else                                         return (int32_t)a;\n}\n\n/**\n * Clip a signed integer into the -(2^p),(2^p-1) range.\n * @param  a value to clip\n * @param  p bit position to clip at\n * @return clipped value\n */\nstatic av_always_inline av_const int av_clip_intp2_c(int a, int p)\n{\n    if (((unsigned)a + (1 << p)) & ~((2 << p) - 1))\n        return (a >> 31) ^ ((1 << p) - 1);\n    else\n        return a;\n}\n\n/**\n * Clip a signed integer to an unsigned power of two range.\n * @param  a value to clip\n * @param  p bit position to clip at\n * @return clipped value\n */\nstatic av_always_inline av_const unsigned av_clip_uintp2_c(int a, int p)\n{\n    const unsigned int bits = ((1 << p) - 1);\n    return (((unsigned int)a) <= bits) ? a : ((a < 0) ? 0 : bits);\n}\n\n/**\n * Clear high bits from an unsigned integer starting with specific bit position\n * @param  a value to clip\n * @param  p bit position to clip at\n * @return clipped value\n */\nstatic av_always_inline av_const unsigned av_mod_uintp2_c(unsigned a, unsigned p)\n{\n    return a & ((1U << p) - 1);\n}\n\n/**\n * Add two signed 32-bit values with saturation.\n *\n * @param  a one value\n * @param  b another value\n * @return sum with signed saturation\n */\nstatic av_always_inline int av_sat_add32_c(int a, int b)\n{\n    return av_clipl_int32((int64_t)a + b);\n}\n\n/**\n * Add a doubled value to another value with saturation at both stages.\n *\n * @param  a first value\n * @param  b value doubled and added to a\n * @return sum sat(a + sat(2*b)) with signed saturation\n */\nstatic av_always_inline int av_sat_dadd32_c(int a, int b)\n{\n    return av_sat_add32(a, av_sat_add32(b, b));\n}\n\n/**\n * Subtract two signed 32-bit values with saturation.\n *\n * @param  a one value\n * @param  b another value\n * @return difference with signed saturation\n */\nstatic av_always_inline int av_sat_sub32_c(int a, int b)\n{\n    return av_clipl_int32((int64_t)a - b);\n}\n\n/**\n * Subtract a doubled value from another value with saturation at both stages.\n *\n * @param  a first value\n * @param  b value doubled and subtracted from a\n * @return difference sat(a - sat(2*b)) with signed saturation\n */\nstatic av_always_inline int av_sat_dsub32_c(int a, int b)\n{\n    return av_sat_sub32(a, av_sat_add32(b, b));\n}\n\n/**\n * Add two signed 64-bit values with saturation.\n *\n * @param  a one value\n * @param  b another value\n * @return sum with signed saturation\n */\nstatic av_always_inline int64_t av_sat_add64_c(int64_t a, int64_t b) {\n#if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_add_overflow)\n    int64_t tmp;\n    return !__builtin_add_overflow(a, b, &tmp) ? tmp : (tmp < 0 ? INT64_MAX : INT64_MIN);\n#else\n    if (b >= 0 && a >= INT64_MAX - b)\n        return INT64_MAX;\n    if (b <= 0 && a <= INT64_MIN - b)\n        return INT64_MIN;\n    return a + b;\n#endif\n}\n\n/**\n * Subtract two signed 64-bit values with saturation.\n *\n * @param  a one value\n * @param  b another value\n * @return difference with signed saturation\n */\nstatic av_always_inline int64_t av_sat_sub64_c(int64_t a, int64_t b) {\n#if (!defined(__INTEL_COMPILER) && AV_GCC_VERSION_AT_LEAST(5,1)) || AV_HAS_BUILTIN(__builtin_sub_overflow)\n    int64_t tmp;\n    return !__builtin_sub_overflow(a, b, &tmp) ? tmp : (tmp < 0 ? INT64_MAX : INT64_MIN);\n#else\n    if (b <= 0 && a >= INT64_MAX + b)\n        return INT64_MAX;\n    if (b >= 0 && a <= INT64_MIN + b)\n        return INT64_MIN;\n    return a - b;\n#endif\n}\n\n/**\n * Clip a float value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const float av_clipf_c(float a, float amin, float amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/**\n * Clip a double value into the amin-amax range.\n * @param a value to clip\n * @param amin minimum value of the clip range\n * @param amax maximum value of the clip range\n * @return clipped value\n */\nstatic av_always_inline av_const double av_clipd_c(double a, double amin, double amax)\n{\n#if defined(HAVE_AV_CONFIG_H) && defined(ASSERT_LEVEL) && ASSERT_LEVEL >= 2\n    if (amin > amax) abort();\n#endif\n    if      (a < amin) return amin;\n    else if (a > amax) return amax;\n    else               return a;\n}\n\n/** Compute ceil(log2(x)).\n * @param x value used to compute ceil(log2(x))\n * @return computed ceiling of log2(x)\n */\nstatic av_always_inline av_const int av_ceil_log2_c(int x)\n{\n    return av_log2((x - 1U) << 1);\n}\n\n/**\n * Count number of bits set to one in x\n * @param x value to count bits of\n * @return the number of bits set to one in x\n */\nstatic av_always_inline av_const int av_popcount_c(uint32_t x)\n{\n    x -= (x >> 1) & 0x55555555;\n    x = (x & 0x33333333) + ((x >> 2) & 0x33333333);\n    x = (x + (x >> 4)) & 0x0F0F0F0F;\n    x += x >> 8;\n    return (x + (x >> 16)) & 0x3F;\n}\n\n/**\n * Count number of bits set to one in x\n * @param x value to count bits of\n * @return the number of bits set to one in x\n */\nstatic av_always_inline av_const int av_popcount64_c(uint64_t x)\n{\n    return av_popcount((uint32_t)x) + av_popcount((uint32_t)(x >> 32));\n}\n\nstatic av_always_inline av_const int av_parity_c(uint32_t v)\n{\n    return av_popcount(v) & 1;\n}\n\n#define MKTAG(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))\n#define MKBETAG(a,b,c,d) ((d) | ((c) << 8) | ((b) << 16) | ((unsigned)(a) << 24))\n\n/**\n * Convert a UTF-8 character (up to 4 bytes) to its 32-bit UCS-4 encoded form.\n *\n * @param val      Output value, must be an lvalue of type uint32_t.\n * @param GET_BYTE Expression reading one byte from the input.\n *                 Evaluated up to 7 times (4 for the currently\n *                 assigned Unicode range).  With a memory buffer\n *                 input, this could be *ptr++, or if you want to make sure\n *                 that *ptr stops at the end of a NULL terminated string then\n *                 *ptr ? *ptr++ : 0\n * @param ERROR    Expression to be evaluated on invalid input,\n *                 typically a goto statement.\n *\n * @warning ERROR should not contain a loop control statement which\n * could interact with the internal while loop, and should force an\n * exit from the macro code (e.g. through a goto or a return) in order\n * to prevent undefined results.\n */\n#define GET_UTF8(val, GET_BYTE, ERROR)\\\n    val= (GET_BYTE);\\\n    {\\\n        uint32_t top = (val & 128) >> 1;\\\n        if ((val & 0xc0) == 0x80 || val >= 0xFE)\\\n            {ERROR}\\\n        while (val & top) {\\\n            unsigned int tmp = (GET_BYTE) - 128;\\\n            if(tmp>>6)\\\n                {ERROR}\\\n            val= (val<<6) + tmp;\\\n            top <<= 5;\\\n        }\\\n        val &= (top << 1) - 1;\\\n    }\n\n/**\n * Convert a UTF-16 character (2 or 4 bytes) to its 32-bit UCS-4 encoded form.\n *\n * @param val       Output value, must be an lvalue of type uint32_t.\n * @param GET_16BIT Expression returning two bytes of UTF-16 data converted\n *                  to native byte order.  Evaluated one or two times.\n * @param ERROR     Expression to be evaluated on invalid input,\n *                  typically a goto statement.\n */\n#define GET_UTF16(val, GET_16BIT, ERROR)\\\n    val = (GET_16BIT);\\\n    {\\\n        unsigned int hi = val - 0xD800;\\\n        if (hi < 0x800) {\\\n            val = (GET_16BIT) - 0xDC00;\\\n            if (val > 0x3FFU || hi > 0x3FFU)\\\n                {ERROR}\\\n            val += (hi<<10) + 0x10000;\\\n        }\\\n    }\\\n\n/**\n * @def PUT_UTF8(val, tmp, PUT_BYTE)\n * Convert a 32-bit Unicode character to its UTF-8 encoded form (up to 4 bytes long).\n * @param val is an input-only argument and should be of type uint32_t. It holds\n * a UCS-4 encoded Unicode character that is to be converted to UTF-8. If\n * val is given as a function it is executed only once.\n * @param tmp is a temporary variable and should be of type uint8_t. It\n * represents an intermediate value during conversion that is to be\n * output by PUT_BYTE.\n * @param PUT_BYTE writes the converted UTF-8 bytes to any proper destination.\n * It could be a function or a statement, and uses tmp as the input byte.\n * For example, PUT_BYTE could be \"*output++ = tmp;\" PUT_BYTE will be\n * executed up to 4 times for values in the valid UTF-8 range and up to\n * 7 times in the general case, depending on the length of the converted\n * Unicode character.\n */\n#define PUT_UTF8(val, tmp, PUT_BYTE)\\\n    {\\\n        int bytes, shift;\\\n        uint32_t in = val;\\\n        if (in < 0x80) {\\\n            tmp = in;\\\n            PUT_BYTE\\\n        } else {\\\n            bytes = (av_log2(in) + 4) / 5;\\\n            shift = (bytes - 1) * 6;\\\n            tmp = (256 - (256 >> bytes)) | (in >> shift);\\\n            PUT_BYTE\\\n            while (shift >= 6) {\\\n                shift -= 6;\\\n                tmp = 0x80 | ((in >> shift) & 0x3f);\\\n                PUT_BYTE\\\n            }\\\n        }\\\n    }\n\n/**\n * @def PUT_UTF16(val, tmp, PUT_16BIT)\n * Convert a 32-bit Unicode character to its UTF-16 encoded form (2 or 4 bytes).\n * @param val is an input-only argument and should be of type uint32_t. It holds\n * a UCS-4 encoded Unicode character that is to be converted to UTF-16. If\n * val is given as a function it is executed only once.\n * @param tmp is a temporary variable and should be of type uint16_t. It\n * represents an intermediate value during conversion that is to be\n * output by PUT_16BIT.\n * @param PUT_16BIT writes the converted UTF-16 data to any proper destination\n * in desired endianness. It could be a function or a statement, and uses tmp\n * as the input byte.  For example, PUT_BYTE could be \"*output++ = tmp;\"\n * PUT_BYTE will be executed 1 or 2 times depending on input character.\n */\n#define PUT_UTF16(val, tmp, PUT_16BIT)\\\n    {\\\n        uint32_t in = val;\\\n        if (in < 0x10000) {\\\n            tmp = in;\\\n            PUT_16BIT\\\n        } else {\\\n            tmp = 0xD800 | ((in - 0x10000) >> 10);\\\n            PUT_16BIT\\\n            tmp = 0xDC00 | ((in - 0x10000) & 0x3FF);\\\n            PUT_16BIT\\\n        }\\\n    }\\\n\n\n\n#include \"mem.h\"\n\n#ifdef HAVE_AV_CONFIG_H\n#    include \"internal.h\"\n#endif /* HAVE_AV_CONFIG_H */\n\n#endif /* AVUTIL_COMMON_H */\n\n/*\n * The following definitions are outside the multiple inclusion guard\n * to ensure they are immediately available in intmath.h.\n */\n\n#ifndef av_ceil_log2\n#   define av_ceil_log2     av_ceil_log2_c\n#endif\n#ifndef av_clip\n#   define av_clip          av_clip_c\n#endif\n#ifndef av_clip64\n#   define av_clip64        av_clip64_c\n#endif\n#ifndef av_clip_uint8\n#   define av_clip_uint8    av_clip_uint8_c\n#endif\n#ifndef av_clip_int8\n#   define av_clip_int8     av_clip_int8_c\n#endif\n#ifndef av_clip_uint16\n#   define av_clip_uint16   av_clip_uint16_c\n#endif\n#ifndef av_clip_int16\n#   define av_clip_int16    av_clip_int16_c\n#endif\n#ifndef av_clipl_int32\n#   define av_clipl_int32   av_clipl_int32_c\n#endif\n#ifndef av_clip_intp2\n#   define av_clip_intp2    av_clip_intp2_c\n#endif\n#ifndef av_clip_uintp2\n#   define av_clip_uintp2   av_clip_uintp2_c\n#endif\n#ifndef av_mod_uintp2\n#   define av_mod_uintp2    av_mod_uintp2_c\n#endif\n#ifndef av_sat_add32\n#   define av_sat_add32     av_sat_add32_c\n#endif\n#ifndef av_sat_dadd32\n#   define av_sat_dadd32    av_sat_dadd32_c\n#endif\n#ifndef av_sat_sub32\n#   define av_sat_sub32     av_sat_sub32_c\n#endif\n#ifndef av_sat_dsub32\n#   define av_sat_dsub32    av_sat_dsub32_c\n#endif\n#ifndef av_sat_add64\n#   define av_sat_add64     av_sat_add64_c\n#endif\n#ifndef av_sat_sub64\n#   define av_sat_sub64     av_sat_sub64_c\n#endif\n#ifndef av_clipf\n#   define av_clipf         av_clipf_c\n#endif\n#ifndef av_clipd\n#   define av_clipd         av_clipd_c\n#endif\n#ifndef av_popcount\n#   define av_popcount      av_popcount_c\n#endif\n#ifndef av_popcount64\n#   define av_popcount64    av_popcount64_c\n#endif\n#ifndef av_parity\n#   define av_parity        av_parity_c\n#endif\n"
  },
  {
    "path": "ffmpeg-4.3.2-experimental-patch/hevcdsp_template.before.c",
    "content": "/*\n * HEVC video decoder\n *\n * Copyright (C) 2012 - 2013 Guillaume Martres\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#include \"get_bits.h\"\n#include \"hevcdec.h\"\n\n#include \"bit_depth_template.c\"\n#include \"hevcdsp.h\"\n\nstatic void FUNC(put_pcm)(uint8_t *_dst, ptrdiff_t stride, int width, int height,\n                          GetBitContext *gb, int pcm_bit_depth)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n\n    stride /= sizeof(pixel);\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = get_bits(gb, pcm_bit_depth) << (BIT_DEPTH - pcm_bit_depth);\n        dst += stride;\n    }\n}\n\nstatic av_always_inline void FUNC(add_residual)(uint8_t *_dst, int16_t *res,\n                                                ptrdiff_t stride, int size)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n\n    stride /= sizeof(pixel);\n\n    for (y = 0; y < size; y++) {\n        for (x = 0; x < size; x++) {\n            dst[x] = av_clip_pixel(dst[x] + *res);\n            res++;\n        }\n        dst += stride;\n    }\n}\n\nstatic void FUNC(add_residual4x4)(uint8_t *_dst, int16_t *res,\n                                  ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 4);\n}\n\nstatic void FUNC(add_residual8x8)(uint8_t *_dst, int16_t *res,\n                                  ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 8);\n}\n\nstatic void FUNC(add_residual16x16)(uint8_t *_dst, int16_t *res,\n                                    ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 16);\n}\n\nstatic void FUNC(add_residual32x32)(uint8_t *_dst, int16_t *res,\n                                    ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 32);\n}\n\nstatic void FUNC(transform_rdpcm)(int16_t *_coeffs, int16_t log2_size, int mode)\n{\n    int16_t *coeffs = (int16_t *) _coeffs;\n    int x, y;\n    int size = 1 << log2_size;\n\n    if (mode) {\n        coeffs += size;\n        for (y = 0; y < size - 1; y++) {\n            for (x = 0; x < size; x++)\n                coeffs[x] += coeffs[x - size];\n            coeffs += size;\n        }\n    } else {\n        for (y = 0; y < size; y++) {\n            for (x = 1; x < size; x++)\n                coeffs[x] += coeffs[x - 1];\n            coeffs += size;\n        }\n    }\n}\n\nstatic void FUNC(dequant)(int16_t *coeffs, int16_t log2_size)\n{\n    int shift  = 15 - BIT_DEPTH - log2_size;\n    int x, y;\n    int size = 1 << log2_size;\n\n    if (shift > 0) {\n        int offset = 1 << (shift - 1);\n        for (y = 0; y < size; y++) {\n            for (x = 0; x < size; x++) {\n                *coeffs = (*coeffs + offset) >> shift;\n                coeffs++;\n            }\n        }\n    } else {\n        for (y = 0; y < size; y++) {\n            for (x = 0; x < size; x++) {\n                *coeffs = *(uint16_t*)coeffs << -shift;\n                coeffs++;\n            }\n        }\n    }\n}\n\n#define SET(dst, x)   (dst) = (x)\n#define SCALE(dst, x) (dst) = av_clip_int16(((x) + add) >> shift)\n\n#define TR_4x4_LUMA(dst, src, step, assign)                             \\\n    do {                                                                \\\n        int c0 = src[0 * step] + src[2 * step];                         \\\n        int c1 = src[2 * step] + src[3 * step];                         \\\n        int c2 = src[0 * step] - src[3 * step];                         \\\n        int c3 = 74 * src[1 * step];                                    \\\n                                                                        \\\n        assign(dst[2 * step], 74 * (src[0 * step] -                     \\\n                                    src[2 * step] +                     \\\n                                    src[3 * step]));                    \\\n        assign(dst[0 * step], 29 * c0 + 55 * c1 + c3);                  \\\n        assign(dst[1 * step], 55 * c2 - 29 * c1 + c3);                  \\\n        assign(dst[3 * step], 55 * c0 + 29 * c2 - c3);                  \\\n    } while (0)\n\nstatic void FUNC(transform_4x4_luma)(int16_t *coeffs)\n{\n    int i;\n    int shift    = 7;\n    int add      = 1 << (shift - 1);\n    int16_t *src = coeffs;\n\n    for (i = 0; i < 4; i++) {\n        TR_4x4_LUMA(src, src, 4, SCALE);\n        src++;\n    }\n\n    shift = 20 - BIT_DEPTH;\n    add   = 1 << (shift - 1);\n    for (i = 0; i < 4; i++) {\n        TR_4x4_LUMA(coeffs, coeffs, 1, SCALE);\n        coeffs += 4;\n    }\n}\n\n#undef TR_4x4_LUMA\n\n#define TR_4(dst, src, dstep, sstep, assign, end)                 \\\n    do {                                                          \\\n        const int e0 = 64 * src[0 * sstep] + 64 * src[2 * sstep]; \\\n        const int e1 = 64 * src[0 * sstep] - 64 * src[2 * sstep]; \\\n        const int o0 = 83 * src[1 * sstep] + 36 * src[3 * sstep]; \\\n        const int o1 = 36 * src[1 * sstep] - 83 * src[3 * sstep]; \\\n                                                                  \\\n        assign(dst[0 * dstep], e0 + o0);                          \\\n        assign(dst[1 * dstep], e1 + o1);                          \\\n        assign(dst[2 * dstep], e1 - o1);                          \\\n        assign(dst[3 * dstep], e0 - o0);                          \\\n    } while (0)\n\n#define TR_8(dst, src, dstep, sstep, assign, end)                 \\\n    do {                                                          \\\n        int i, j;                                                 \\\n        int e_8[4];                                               \\\n        int o_8[4] = { 0 };                                       \\\n        for (i = 0; i < 4; i++)                                   \\\n            for (j = 1; j < end; j += 2)                          \\\n                o_8[i] += transform[4 * j][i] * src[j * sstep];   \\\n        TR_4(e_8, src, 1, 2 * sstep, SET, 4);                     \\\n                                                                  \\\n        for (i = 0; i < 4; i++) {                                 \\\n            assign(dst[i * dstep], e_8[i] + o_8[i]);              \\\n            assign(dst[(7 - i) * dstep], e_8[i] - o_8[i]);        \\\n        }                                                         \\\n    } while (0)\n\n#define TR_16(dst, src, dstep, sstep, assign, end)                \\\n    do {                                                          \\\n        int i, j;                                                 \\\n        int e_16[8];                                              \\\n        int o_16[8] = { 0 };                                      \\\n        for (i = 0; i < 8; i++)                                   \\\n            for (j = 1; j < end; j += 2)                          \\\n                o_16[i] += transform[2 * j][i] * src[j * sstep];  \\\n        TR_8(e_16, src, 1, 2 * sstep, SET, 8);                    \\\n                                                                  \\\n        for (i = 0; i < 8; i++) {                                 \\\n            assign(dst[i * dstep], e_16[i] + o_16[i]);            \\\n            assign(dst[(15 - i) * dstep], e_16[i] - o_16[i]);     \\\n        }                                                         \\\n    } while (0)\n\n#define TR_32(dst, src, dstep, sstep, assign, end)                \\\n    do {                                                          \\\n        int i, j;                                                 \\\n        int e_32[16];                                             \\\n        int o_32[16] = { 0 };                                     \\\n        for (i = 0; i < 16; i++)                                  \\\n            for (j = 1; j < end; j += 2)                          \\\n                o_32[i] += transform[j][i] * src[j * sstep];      \\\n        TR_16(e_32, src, 1, 2 * sstep, SET, end / 2);             \\\n                                                                  \\\n        for (i = 0; i < 16; i++) {                                \\\n            assign(dst[i * dstep], e_32[i] + o_32[i]);            \\\n            assign(dst[(31 - i) * dstep], e_32[i] - o_32[i]);     \\\n        }                                                         \\\n    } while (0)\n\n#define IDCT_VAR4(H)                                              \\\n    int limit2 = FFMIN(col_limit + 4, H)\n#define IDCT_VAR8(H)                                              \\\n    int limit  = FFMIN(col_limit, H);                             \\\n    int limit2 = FFMIN(col_limit + 4, H)\n#define IDCT_VAR16(H)   IDCT_VAR8(H)\n#define IDCT_VAR32(H)   IDCT_VAR8(H)\n\n#define IDCT(H)                                                   \\\nstatic void FUNC(idct_ ## H ## x ## H )(int16_t *coeffs,          \\\n                                        int col_limit)            \\\n{                                                                 \\\n    int i;                                                        \\\n    int      shift = 7;                                           \\\n    int      add   = 1 << (shift - 1);                            \\\n    int16_t *src   = coeffs;                                      \\\n    IDCT_VAR ## H(H);                                             \\\n                                                                  \\\n    for (i = 0; i < H; i++) {                                     \\\n        TR_ ## H(src, src, H, H, SCALE, limit2);                  \\\n        if (limit2 < H && i%4 == 0 && !!i)                        \\\n            limit2 -= 4;                                          \\\n        src++;                                                    \\\n    }                                                             \\\n                                                                  \\\n    shift = 20 - BIT_DEPTH;                                       \\\n    add   = 1 << (shift - 1);                                     \\\n    for (i = 0; i < H; i++) {                                     \\\n        TR_ ## H(coeffs, coeffs, 1, 1, SCALE, limit);             \\\n        coeffs += H;                                              \\\n    }                                                             \\\n}\n\n#define IDCT_DC(H)                                                \\\nstatic void FUNC(idct_ ## H ## x ## H ## _dc)(int16_t *coeffs)    \\\n{                                                                 \\\n    int i, j;                                                     \\\n    int shift = 14 - BIT_DEPTH;                                   \\\n    int add   = 1 << (shift - 1);                                 \\\n    int coeff = (((coeffs[0] + 1) >> 1) + add) >> shift;          \\\n                                                                  \\\n    for (j = 0; j < H; j++) {                                     \\\n        for (i = 0; i < H; i++) {                                 \\\n            coeffs[i + j * H] = coeff;                            \\\n        }                                                         \\\n    }                                                             \\\n}\n\nIDCT( 4)\nIDCT( 8)\nIDCT(16)\nIDCT(32)\n\nIDCT_DC( 4)\nIDCT_DC( 8)\nIDCT_DC(16)\nIDCT_DC(32)\n\n#undef TR_4\n#undef TR_8\n#undef TR_16\n#undef TR_32\n\n#undef SET\n#undef SCALE\n\nstatic void FUNC(sao_band_filter)(uint8_t *_dst, uint8_t *_src,\n                                  ptrdiff_t stride_dst, ptrdiff_t stride_src,\n                                  int16_t *sao_offset_val, int sao_left_class,\n                                  int width, int height)\n{\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int offset_table[32] = { 0 };\n    int k, y, x;\n    int shift  = BIT_DEPTH - 5;\n\n    stride_dst /= sizeof(pixel);\n    stride_src /= sizeof(pixel);\n\n    for (k = 0; k < 4; k++)\n        offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1];\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(src[x] + offset_table[src[x] >> shift]);\n        dst += stride_dst;\n        src += stride_src;\n    }\n}\n\n#define CMP(a, b) (((a) > (b)) - ((a) < (b)))\n\nstatic void FUNC(sao_edge_filter)(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val,\n                                  int eo, int width, int height) {\n\n    static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 };\n    static const int8_t pos[4][2][2] = {\n        { { -1,  0 }, {  1, 0 } }, // horizontal\n        { {  0, -1 }, {  0, 1 } }, // vertical\n        { { -1, -1 }, {  1, 1 } }, // 45 degree\n        { {  1, -1 }, { -1, 1 } }, // 135 degree\n    };\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int a_stride, b_stride;\n    int x, y;\n    ptrdiff_t stride_src = (2*MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE) / sizeof(pixel);\n    stride_dst /= sizeof(pixel);\n\n    a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src;\n    b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src;\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            int diff0 = CMP(src[x], src[x + a_stride]);\n            int diff1 = CMP(src[x], src[x + b_stride]);\n            int offset_val        = edge_idx[2 + diff0 + diff1];\n            dst[x] = av_clip_pixel(src[x] + sao_offset_val[offset_val]);\n        }\n        src += stride_src;\n        dst += stride_dst;\n    }\n}\n\nstatic void FUNC(sao_edge_restore_0)(uint8_t *_dst, uint8_t *_src,\n                                    ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao,\n                                    int *borders, int _width, int _height,\n                                    int c_idx, uint8_t *vert_edge,\n                                    uint8_t *horiz_edge, uint8_t *diag_edge)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int16_t *sao_offset_val = sao->offset_val[c_idx];\n    int sao_eo_class    = sao->eo_class[c_idx];\n    int init_x = 0, width = _width, height = _height;\n\n    stride_dst /= sizeof(pixel);\n    stride_src /= sizeof(pixel);\n\n    if (sao_eo_class != SAO_EO_VERT) {\n        if (borders[0]) {\n            int offset_val = sao_offset_val[0];\n            for (y = 0; y < height; y++) {\n                dst[y * stride_dst] = av_clip_pixel(src[y * stride_src] + offset_val);\n            }\n            init_x = 1;\n        }\n        if (borders[2]) {\n            int offset_val = sao_offset_val[0];\n            int offset     = width - 1;\n            for (x = 0; x < height; x++) {\n                dst[x * stride_dst + offset] = av_clip_pixel(src[x * stride_src + offset] + offset_val);\n            }\n            width--;\n        }\n    }\n    if (sao_eo_class != SAO_EO_HORIZ) {\n        if (borders[1]) {\n            int offset_val = sao_offset_val[0];\n            for (x = init_x; x < width; x++)\n                dst[x] = av_clip_pixel(src[x] + offset_val);\n        }\n        if (borders[3]) {\n            int offset_val   = sao_offset_val[0];\n            ptrdiff_t y_stride_dst = stride_dst * (height - 1);\n            ptrdiff_t y_stride_src = stride_src * (height - 1);\n            for (x = init_x; x < width; x++)\n                dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + offset_val);\n            height--;\n        }\n    }\n}\n\nstatic void FUNC(sao_edge_restore_1)(uint8_t *_dst, uint8_t *_src,\n                                    ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao,\n                                    int *borders, int _width, int _height,\n                                    int c_idx, uint8_t *vert_edge,\n                                    uint8_t *horiz_edge, uint8_t *diag_edge)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int16_t *sao_offset_val = sao->offset_val[c_idx];\n    int sao_eo_class    = sao->eo_class[c_idx];\n    int init_x = 0, init_y = 0, width = _width, height = _height;\n\n    stride_dst /= sizeof(pixel);\n    stride_src /= sizeof(pixel);\n\n    if (sao_eo_class != SAO_EO_VERT) {\n        if (borders[0]) {\n            int offset_val = sao_offset_val[0];\n            for (y = 0; y < height; y++) {\n                dst[y * stride_dst] = av_clip_pixel(src[y * stride_src] + offset_val);\n            }\n            init_x = 1;\n        }\n        if (borders[2]) {\n            int offset_val = sao_offset_val[0];\n            int offset     = width - 1;\n            for (x = 0; x < height; x++) {\n                dst[x * stride_dst + offset] = av_clip_pixel(src[x * stride_src + offset] + offset_val);\n            }\n            width--;\n        }\n    }\n    if (sao_eo_class != SAO_EO_HORIZ) {\n        if (borders[1]) {\n            int offset_val = sao_offset_val[0];\n            for (x = init_x; x < width; x++)\n                dst[x] = av_clip_pixel(src[x] + offset_val);\n            init_y = 1;\n        }\n        if (borders[3]) {\n            int offset_val   = sao_offset_val[0];\n            ptrdiff_t y_stride_dst = stride_dst * (height - 1);\n            ptrdiff_t y_stride_src = stride_src * (height - 1);\n            for (x = init_x; x < width; x++)\n                dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + offset_val);\n            height--;\n        }\n    }\n\n    {\n        int save_upper_left  = !diag_edge[0] && sao_eo_class == SAO_EO_135D && !borders[0] && !borders[1];\n        int save_upper_right = !diag_edge[1] && sao_eo_class == SAO_EO_45D  && !borders[1] && !borders[2];\n        int save_lower_right = !diag_edge[2] && sao_eo_class == SAO_EO_135D && !borders[2] && !borders[3];\n        int save_lower_left  = !diag_edge[3] && sao_eo_class == SAO_EO_45D  && !borders[0] && !borders[3];\n\n        // Restore pixels that can't be modified\n        if(vert_edge[0] && sao_eo_class != SAO_EO_VERT) {\n            for(y = init_y+save_upper_left; y< height-save_lower_left; y++)\n                dst[y*stride_dst] = src[y*stride_src];\n        }\n        if(vert_edge[1] && sao_eo_class != SAO_EO_VERT) {\n            for(y = init_y+save_upper_right; y< height-save_lower_right; y++)\n                dst[y*stride_dst+width-1] = src[y*stride_src+width-1];\n        }\n\n        if(horiz_edge[0] && sao_eo_class != SAO_EO_HORIZ) {\n            for(x = init_x+save_upper_left; x < width-save_upper_right; x++)\n                dst[x] = src[x];\n        }\n        if(horiz_edge[1] && sao_eo_class != SAO_EO_HORIZ) {\n            for(x = init_x+save_lower_left; x < width-save_lower_right; x++)\n                dst[(height-1)*stride_dst+x] = src[(height-1)*stride_src+x];\n        }\n        if(diag_edge[0] && sao_eo_class == SAO_EO_135D)\n            dst[0] = src[0];\n        if(diag_edge[1] && sao_eo_class == SAO_EO_45D)\n            dst[width-1] = src[width-1];\n        if(diag_edge[2] && sao_eo_class == SAO_EO_135D)\n            dst[stride_dst*(height-1)+width-1] = src[stride_src*(height-1)+width-1];\n        if(diag_edge[3] && sao_eo_class == SAO_EO_45D)\n            dst[stride_dst*(height-1)] = src[stride_src*(height-1)];\n\n    }\n}\n\n#undef CMP\n\n////////////////////////////////////////////////////////////////////////////////\n//\n////////////////////////////////////////////////////////////////////////////////\nstatic void FUNC(put_hevc_pel_pixels)(int16_t *dst,\n                                      uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = src[x] << (14 - BIT_DEPTH);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_uni_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                          int height, intptr_t mx, intptr_t my, int width)\n{\n    int y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    for (y = 0; y < height; y++) {\n        memcpy(dst, src, width * sizeof(pixel));\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_bi_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                         int16_t *src2,\n                                         int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14  + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((src[x] << (14 - BIT_DEPTH)) + src2[x] + offset) >> shift);\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_uni_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                            int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((src[x] << (14 - BIT_DEPTH)) * wx + offset) >> shift) + ox);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_bi_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                           int16_t *src2,\n                                           int height, int denom, int wx0, int wx1,\n                                           int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14  + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel(( (src[x] << (14 - BIT_DEPTH)) * wx1 + src2[x] * wx0 + (ox0 + ox1 + 1) * (1 << log2Wd)) >> (log2Wd + 1));\n        }\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//\n////////////////////////////////////////////////////////////////////////////////\n#define QPEL_FILTER(src, stride)                                               \\\n    (filter[0] * src[x - 3 * stride] +                                         \\\n     filter[1] * src[x - 2 * stride] +                                         \\\n     filter[2] * src[x -     stride] +                                         \\\n     filter[3] * src[x             ] +                                         \\\n     filter[4] * src[x +     stride] +                                         \\\n     filter[5] * src[x + 2 * stride] +                                         \\\n     filter[6] * src[x + 3 * stride] +                                         \\\n     filter[7] * src[x + 4 * stride])\n\nstatic void FUNC(put_hevc_qpel_h)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    const int8_t *filter    = ff_hevc_qpel_filters[mx - 1];\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_v)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    const int8_t *filter    = ff_hevc_qpel_filters[my - 1];\n    for (y = 0; y < height; y++)  {\n        for (x = 0; x < width; x++)\n            dst[x] = QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_hv)(int16_t *dst,\n                                   uint8_t *_src,\n                                   ptrdiff_t _srcstride,\n                                   int height, intptr_t mx,\n                                   intptr_t my, int width)\n{\n    int x, y;\n    const int8_t *filter;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n    filter = ff_hevc_qpel_filters[mx - 1];\n    for (y = 0; y < height + QPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_qpel_filters[my - 1];\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6;\n        tmp += MAX_PB_SIZE;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_uni_h)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                      uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter    = ff_hevc_qpel_filters[mx - 1];\n    int shift = 14 - BIT_DEPTH;\n\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + offset) >> shift);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    const int8_t *filter    = ff_hevc_qpel_filters[mx - 1];\n\n    int shift = 14  + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_uni_v)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                     uint8_t *_src, ptrdiff_t _srcstride,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter    = ff_hevc_qpel_filters[my - 1];\n    int shift = 14 - BIT_DEPTH;\n\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + offset) >> shift);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\n\nstatic void FUNC(put_hevc_qpel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    const int8_t *filter    = ff_hevc_qpel_filters[my - 1];\n\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_uni_hv)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                       uint8_t *_src, ptrdiff_t _srcstride,\n                                       int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    const int8_t *filter;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift =  14 - BIT_DEPTH;\n\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n    filter = ff_hevc_qpel_filters[mx - 1];\n    for (y = 0; y < height + QPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_qpel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + offset) >> shift);\n        tmp += MAX_PB_SIZE;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int16_t *src2,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    const int8_t *filter;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n    filter = ff_hevc_qpel_filters[mx - 1];\n    for (y = 0; y < height + QPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_qpel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift);\n        tmp  += MAX_PB_SIZE;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_uni_w_h)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                        uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox,\n                                        intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter    = ff_hevc_qpel_filters[mx - 1];\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    const int8_t *filter    = ff_hevc_qpel_filters[mx - 1];\n\n    int shift = 14  + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_uni_w_v)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                        uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox,\n                                        intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter    = ff_hevc_qpel_filters[my - 1];\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    const int8_t *filter    = ff_hevc_qpel_filters[my - 1];\n\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_uni_w_hv)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                         uint8_t *_src, ptrdiff_t _srcstride,\n                                         int height, int denom, int wx, int ox,\n                                         intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    const int8_t *filter;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n    filter = ff_hevc_qpel_filters[mx - 1];\n    for (y = 0; y < height + QPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_qpel_filters[my - 1];\n\n    ox = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx + offset) >> shift) + ox);\n        tmp += MAX_PB_SIZE;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_qpel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int16_t *src2,\n                                        int height, int denom, int wx0, int wx1,\n                                        int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    const int8_t *filter;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n    filter = ff_hevc_qpel_filters[mx - 1];\n    for (y = 0; y < height + QPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_qpel_filters[my - 1];\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));\n        tmp  += MAX_PB_SIZE;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//\n////////////////////////////////////////////////////////////////////////////////\n#define EPEL_FILTER(src, stride)                                               \\\n    (filter[0] * src[x - stride] +                                             \\\n     filter[1] * src[x]          +                                             \\\n     filter[2] * src[x + stride] +                                             \\\n     filter[3] * src[x + 2 * stride])\n\nstatic void FUNC(put_hevc_epel_h)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_v)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_hv)(int16_t *dst,\n                                   uint8_t *_src, ptrdiff_t _srcstride,\n                                   int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6;\n        tmp += MAX_PB_SIZE;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + offset) >> shift);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);\n        }\n        dst  += dststride;\n        src  += srcstride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    int shift = 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + offset) >> shift);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);\n        dst  += dststride;\n        src  += srcstride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + offset) >> shift);\n        tmp += MAX_PB_SIZE;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int16_t *src2,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift);\n        tmp  += MAX_PB_SIZE;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel((((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);\n        }\n        dst += dststride;\n        src += srcstride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel((((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);\n        }\n        dst += dststride;\n        src += srcstride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                         int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx + offset) >> shift) + ox);\n        tmp += MAX_PB_SIZE;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int16_t *src2,\n                                        int height, int denom, int wx0, int wx1,\n                                        int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));\n        tmp  += MAX_PB_SIZE;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\n// line zero\n#define P3 pix[-4 * xstride]\n#define P2 pix[-3 * xstride]\n#define P1 pix[-2 * xstride]\n#define P0 pix[-1 * xstride]\n#define Q0 pix[0 * xstride]\n#define Q1 pix[1 * xstride]\n#define Q2 pix[2 * xstride]\n#define Q3 pix[3 * xstride]\n\n// line three. used only for deblocking decision\n#define TP3 pix[-4 * xstride + 3 * ystride]\n#define TP2 pix[-3 * xstride + 3 * ystride]\n#define TP1 pix[-2 * xstride + 3 * ystride]\n#define TP0 pix[-1 * xstride + 3 * ystride]\n#define TQ0 pix[0  * xstride + 3 * ystride]\n#define TQ1 pix[1  * xstride + 3 * ystride]\n#define TQ2 pix[2  * xstride + 3 * ystride]\n#define TQ3 pix[3  * xstride + 3 * ystride]\n\nstatic void FUNC(hevc_loop_filter_luma)(uint8_t *_pix,\n                                        ptrdiff_t _xstride, ptrdiff_t _ystride,\n                                        int beta, int *_tc,\n                                        uint8_t *_no_p, uint8_t *_no_q)\n{\n    int d, j;\n    pixel *pix        = (pixel *)_pix;\n    ptrdiff_t xstride = _xstride / sizeof(pixel);\n    ptrdiff_t ystride = _ystride / sizeof(pixel);\n\n    beta <<= BIT_DEPTH - 8;\n\n    for (j = 0; j < 2; j++) {\n        const int dp0  = abs(P2  - 2 * P1  + P0);\n        const int dq0  = abs(Q2  - 2 * Q1  + Q0);\n        const int dp3  = abs(TP2 - 2 * TP1 + TP0);\n        const int dq3  = abs(TQ2 - 2 * TQ1 + TQ0);\n        const int d0   = dp0 + dq0;\n        const int d3   = dp3 + dq3;\n        const int tc   = _tc[j]   << (BIT_DEPTH - 8);\n        const int no_p = _no_p[j];\n        const int no_q = _no_q[j];\n\n        if (d0 + d3 >= beta) {\n            pix += 4 * ystride;\n            continue;\n        } else {\n            const int beta_3 = beta >> 3;\n            const int beta_2 = beta >> 2;\n            const int tc25   = ((tc * 5 + 1) >> 1);\n\n            if (abs(P3  -  P0) + abs(Q3  -  Q0) < beta_3 && abs(P0  -  Q0) < tc25 &&\n                abs(TP3 - TP0) + abs(TQ3 - TQ0) < beta_3 && abs(TP0 - TQ0) < tc25 &&\n                                      (d0 << 1) < beta_2 &&      (d3 << 1) < beta_2) {\n                // strong filtering\n                const int tc2 = tc << 1;\n                for (d = 0; d < 4; d++) {\n                    const int p3 = P3;\n                    const int p2 = P2;\n                    const int p1 = P1;\n                    const int p0 = P0;\n                    const int q0 = Q0;\n                    const int q1 = Q1;\n                    const int q2 = Q2;\n                    const int q3 = Q3;\n                    if (!no_p) {\n                        P0 = p0 + av_clip(((p2 + 2 * p1 + 2 * p0 + 2 * q0 + q1 + 4) >> 3) - p0, -tc2, tc2);\n                        P1 = p1 + av_clip(((p2 + p1 + p0 + q0 + 2) >> 2) - p1, -tc2, tc2);\n                        P2 = p2 + av_clip(((2 * p3 + 3 * p2 + p1 + p0 + q0 + 4) >> 3) - p2, -tc2, tc2);\n                    }\n                    if (!no_q) {\n                        Q0 = q0 + av_clip(((p1 + 2 * p0 + 2 * q0 + 2 * q1 + q2 + 4) >> 3) - q0, -tc2, tc2);\n                        Q1 = q1 + av_clip(((p0 + q0 + q1 + q2 + 2) >> 2) - q1, -tc2, tc2);\n                        Q2 = q2 + av_clip(((2 * q3 + 3 * q2 + q1 + q0 + p0 + 4) >> 3) - q2, -tc2, tc2);\n                    }\n                    pix += ystride;\n                }\n            } else { // normal filtering\n                int nd_p = 1;\n                int nd_q = 1;\n                const int tc_2 = tc >> 1;\n                if (dp0 + dp3 < ((beta + (beta >> 1)) >> 3))\n                    nd_p = 2;\n                if (dq0 + dq3 < ((beta + (beta >> 1)) >> 3))\n                    nd_q = 2;\n\n                for (d = 0; d < 4; d++) {\n                    const int p2 = P2;\n                    const int p1 = P1;\n                    const int p0 = P0;\n                    const int q0 = Q0;\n                    const int q1 = Q1;\n                    const int q2 = Q2;\n                    int delta0   = (9 * (q0 - p0) - 3 * (q1 - p1) + 8) >> 4;\n                    if (abs(delta0) < 10 * tc) {\n                        delta0 = av_clip(delta0, -tc, tc);\n                        if (!no_p)\n                            P0 = av_clip_pixel(p0 + delta0);\n                        if (!no_q)\n                            Q0 = av_clip_pixel(q0 - delta0);\n                        if (!no_p && nd_p > 1) {\n                            const int deltap1 = av_clip((((p2 + p0 + 1) >> 1) - p1 + delta0) >> 1, -tc_2, tc_2);\n                            P1 = av_clip_pixel(p1 + deltap1);\n                        }\n                        if (!no_q && nd_q > 1) {\n                            const int deltaq1 = av_clip((((q2 + q0 + 1) >> 1) - q1 - delta0) >> 1, -tc_2, tc_2);\n                            Q1 = av_clip_pixel(q1 + deltaq1);\n                        }\n                    }\n                    pix += ystride;\n                }\n            }\n        }\n    }\n}\n\nstatic void FUNC(hevc_loop_filter_chroma)(uint8_t *_pix, ptrdiff_t _xstride,\n                                          ptrdiff_t _ystride, int *_tc,\n                                          uint8_t *_no_p, uint8_t *_no_q)\n{\n    int d, j, no_p, no_q;\n    pixel *pix        = (pixel *)_pix;\n    ptrdiff_t xstride = _xstride / sizeof(pixel);\n    ptrdiff_t ystride = _ystride / sizeof(pixel);\n\n    for (j = 0; j < 2; j++) {\n        const int tc = _tc[j] << (BIT_DEPTH - 8);\n        if (tc <= 0) {\n            pix += 4 * ystride;\n            continue;\n        }\n        no_p = _no_p[j];\n        no_q = _no_q[j];\n\n        for (d = 0; d < 4; d++) {\n            int delta0;\n            const int p1 = P1;\n            const int p0 = P0;\n            const int q0 = Q0;\n            const int q1 = Q1;\n            delta0 = av_clip((((q0 - p0) * 4) + p1 - q1 + 4) >> 3, -tc, tc);\n            if (!no_p)\n                P0 = av_clip_pixel(p0 + delta0);\n            if (!no_q)\n                Q0 = av_clip_pixel(q0 - delta0);\n            pix += ystride;\n        }\n    }\n}\n\nstatic void FUNC(hevc_h_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,\n                                            int32_t *tc, uint8_t *no_p,\n                                            uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_chroma)(pix, stride, sizeof(pixel), tc, no_p, no_q);\n}\n\nstatic void FUNC(hevc_v_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,\n                                            int32_t *tc, uint8_t *no_p,\n                                            uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_chroma)(pix, sizeof(pixel), stride, tc, no_p, no_q);\n}\n\nstatic void FUNC(hevc_h_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,\n                                          int beta, int32_t *tc, uint8_t *no_p,\n                                          uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_luma)(pix, stride, sizeof(pixel),\n                                beta, tc, no_p, no_q);\n}\n\nstatic void FUNC(hevc_v_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,\n                                          int beta, int32_t *tc, uint8_t *no_p,\n                                          uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_luma)(pix, sizeof(pixel), stride,\n                                beta, tc, no_p, no_q);\n}\n\n#undef P3\n#undef P2\n#undef P1\n#undef P0\n#undef Q0\n#undef Q1\n#undef Q2\n#undef Q3\n\n#undef TP3\n#undef TP2\n#undef TP1\n#undef TP0\n#undef TQ0\n#undef TQ1\n#undef TQ2\n#undef TQ3\n"
  },
  {
    "path": "ffmpeg-4.3.2-experimental-patch/hevcdsp_template.c",
    "content": "/*\n * HEVC video decoder\n *\n * Copyright (C) 2012 - 2013 Guillaume Martres\n *\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifdef _MSC_VER\n#include <emmintrin.h>\n#endif\n\n#include \"get_bits.h\"\n#include \"hevcdec.h\"\n\n#include \"bit_depth_template.c\"\n#include \"hevcdsp.h\"\n\nstatic void FUNC(put_pcm)(uint8_t *_dst, ptrdiff_t stride, int width, int height,\n                          GetBitContext *gb, int pcm_bit_depth)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n\n    stride /= sizeof(pixel);\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = get_bits(gb, pcm_bit_depth) << (BIT_DEPTH - pcm_bit_depth);\n        dst += stride;\n    }\n}\n\nstatic av_always_inline void FUNC(add_residual)(uint8_t *_dst, int16_t *res,\n                                                ptrdiff_t stride, int size)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n\n    stride /= sizeof(pixel);\n\n    for (y = 0; y < size; y++) {\n        for (x = 0; x < size; x++) {\n            dst[x] = av_clip_pixel(dst[x] + *res);\n            res++;\n        }\n        dst += stride;\n    }\n}\n\nstatic void FUNC(add_residual4x4)(uint8_t *_dst, int16_t *res,\n                                  ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 4);\n}\n\nstatic void FUNC(add_residual8x8)(uint8_t *_dst, int16_t *res,\n                                  ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 8);\n}\n\nstatic void FUNC(add_residual16x16)(uint8_t *_dst, int16_t *res,\n                                    ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 16);\n}\n\nstatic void FUNC(add_residual32x32)(uint8_t *_dst, int16_t *res,\n                                    ptrdiff_t stride)\n{\n    FUNC(add_residual)(_dst, res, stride, 32);\n}\n\nstatic void FUNC(transform_rdpcm)(int16_t *_coeffs, int16_t log2_size, int mode)\n{\n    int16_t *coeffs = (int16_t *) _coeffs;\n    int x, y;\n    int size = 1 << log2_size;\n\n    if (mode) {\n        coeffs += size;\n        for (y = 0; y < size - 1; y++) {\n            for (x = 0; x < size; x++)\n                coeffs[x] += coeffs[x - size];\n            coeffs += size;\n        }\n    } else {\n        for (y = 0; y < size; y++) {\n            for (x = 1; x < size; x++)\n                coeffs[x] += coeffs[x - 1];\n            coeffs += size;\n        }\n    }\n}\n\nstatic void FUNC(dequant)(int16_t *coeffs, int16_t log2_size)\n{\n    int shift  = 15 - BIT_DEPTH - log2_size;\n    int x, y;\n    int size = 1 << log2_size;\n\n    if (shift > 0) {\n        int offset = 1 << (shift - 1);\n        for (y = 0; y < size; y++) {\n            for (x = 0; x < size; x++) {\n                *coeffs = (*coeffs + offset) >> shift;\n                coeffs++;\n            }\n        }\n    } else {\n        for (y = 0; y < size; y++) {\n            for (x = 0; x < size; x++) {\n                *coeffs = *(uint16_t*)coeffs << -shift;\n                coeffs++;\n            }\n        }\n    }\n}\n\n#define SET(dst, x)   (dst) = (x)\n#define SCALE(dst, x) (dst) = av_clip_int16(((x) + add) >> shift)\n\n#define TR_4x4_LUMA(dst, src, step, assign)                             \\\n    do {                                                                \\\n        int c0 = src[0 * step] + src[2 * step];                         \\\n        int c1 = src[2 * step] + src[3 * step];                         \\\n        int c2 = src[0 * step] - src[3 * step];                         \\\n        int c3 = 74 * src[1 * step];                                    \\\n                                                                        \\\n        assign(dst[2 * step], 74 * (src[0 * step] -                     \\\n                                    src[2 * step] +                     \\\n                                    src[3 * step]));                    \\\n        assign(dst[0 * step], 29 * c0 + 55 * c1 + c3);                  \\\n        assign(dst[1 * step], 55 * c2 - 29 * c1 + c3);                  \\\n        assign(dst[3 * step], 55 * c0 + 29 * c2 - c3);                  \\\n    } while (0)\n\nstatic void FUNC(transform_4x4_luma)(int16_t *coeffs)\n{\n    int i;\n    int shift    = 7;\n    int add      = 1 << (shift - 1);\n    int16_t *src = coeffs;\n\n    for (i = 0; i < 4; i++) {\n        TR_4x4_LUMA(src, src, 4, SCALE);\n        src++;\n    }\n\n    shift = 20 - BIT_DEPTH;\n    add   = 1 << (shift - 1);\n    for (i = 0; i < 4; i++) {\n        TR_4x4_LUMA(coeffs, coeffs, 1, SCALE);\n        coeffs += 4;\n    }\n}\n\n#undef TR_4x4_LUMA\n\n#define TR_4(dst, src, dstep, sstep, assign, end)                 \\\n    do {                                                          \\\n        const int e0 = 64 * src[0 * sstep] + 64 * src[2 * sstep]; \\\n        const int e1 = 64 * src[0 * sstep] - 64 * src[2 * sstep]; \\\n        const int o0 = 83 * src[1 * sstep] + 36 * src[3 * sstep]; \\\n        const int o1 = 36 * src[1 * sstep] - 83 * src[3 * sstep]; \\\n                                                                  \\\n        assign(dst[0 * dstep], e0 + o0);                          \\\n        assign(dst[1 * dstep], e1 + o1);                          \\\n        assign(dst[2 * dstep], e1 - o1);                          \\\n        assign(dst[3 * dstep], e0 - o0);                          \\\n    } while (0)\n\n#define TR_8(dst, src, dstep, sstep, assign, end)                 \\\n    do {                                                          \\\n        int i, j;                                                 \\\n        int e_8[4];                                               \\\n        int o_8[4] = { 0 };                                       \\\n        for (j = 1; j < end; j += 2)                              \\\n            for (i = 0; i < 4; i++)                               \\\n                o_8[i] += transform[4 * j][i] * src[j * sstep];   \\\n        TR_4(e_8, src, 1, 2 * sstep, SET, 4);                     \\\n                                                                  \\\n        for (i = 0; i < 4; i++) {                                 \\\n            assign(dst[i * dstep], e_8[i] + o_8[i]);              \\\n            assign(dst[(7 - i) * dstep], e_8[i] - o_8[i]);        \\\n        }                                                         \\\n    } while (0)\n\n#ifdef _MSC_VER\n\n#define TR_16(dst, src, dstep, sstep, assign, end)                  \\\n    do {                                                            \\\n        int i, j;                                                   \\\n        int e_16[8];                                                \\\n        int o_16[8];                                                \\\n        __m128i o_0, o_1;                                           \\\n        o_0 =  o_1 = _mm_setzero_si128();                           \\\n        for (j = 1; j < end; j += 2) {                              \\\n            __m128i vhi, vlo;                                       \\\n            const short multiplier = src[j * sstep];                \\\n            __m128i coeffs = _mm_set1_epi16(multiplier);            \\\n            __m128i buf = _mm_castpd_si128(_mm_load_sd((const double*) transform[2 * j])); \\\n            buf = _mm_srai_epi16(_mm_unpacklo_epi8(buf, buf), 8);   \\\n            vhi = _mm_mulhi_epi16(buf, coeffs);                     \\\n            vlo = _mm_mullo_epi16(buf, coeffs);                     \\\n            o_0 = _mm_add_epi32(o_0, _mm_unpacklo_epi16(vlo, vhi)); \\\n            o_1 = _mm_add_epi32(o_1, _mm_unpackhi_epi16(vlo, vhi)); \\\n        }                                                           \\\n        ((__m128i*) o_16)[0] = o_0;                                 \\\n        ((__m128i*) o_16)[1] = o_1;                                 \\\n        TR_8(e_16, src, 1, 2 * sstep, SET, 8);                      \\\n                                                                    \\\n        for (i = 0; i < 8; i++) {                                   \\\n            assign(dst[i * dstep], e_16[i] + o_16[i]);              \\\n            assign(dst[(15 - i) * dstep], e_16[i] - o_16[i]);       \\\n        }                                                           \\\n    } while (0)\n\n\n#define TR_32(dst, src, dstep, sstep, assign, end)                  \\\n    do {                                                            \\\n        int i, j;                                                   \\\n        int e_32[16];                                               \\\n        int o_32[16];                                               \\\n        __m128i o_0, o_1, o_2, o_3;                                 \\\n        o_0 =  o_1 =  o_2 = o_3 = _mm_setzero_si128();              \\\n        for (j = 1; j < end; j += 2) {                              \\\n            __m128i vhi, vlo;                                       \\\n            const short multiplier = src[j * sstep];                \\\n            __m128i coeffs = _mm_set1_epi16(multiplier);            \\\n            __m128i buf = _mm_castpd_si128(_mm_load_sd((const double*) transform[j])); \\\n            buf = _mm_srai_epi16(_mm_unpacklo_epi8(buf, buf), 8);   \\\n            vhi = _mm_mulhi_epi16(buf, coeffs);                     \\\n            vlo = _mm_mullo_epi16(buf, coeffs);                     \\\n            o_0 = _mm_add_epi32(o_0, _mm_unpacklo_epi16(vlo, vhi)); \\\n            o_1 = _mm_add_epi32(o_1, _mm_unpackhi_epi16(vlo, vhi)); \\\n            buf = _mm_castpd_si128(_mm_load_sd((const double*) &transform[j][8])); \\\n            buf = _mm_srai_epi16(_mm_unpacklo_epi8(buf, buf), 8);   \\\n            vhi = _mm_mulhi_epi16(buf, coeffs);                     \\\n            vlo = _mm_mullo_epi16(buf, coeffs);                     \\\n            o_2 = _mm_add_epi32(o_2, _mm_unpacklo_epi16(vlo, vhi)); \\\n            o_3 = _mm_add_epi32(o_3, _mm_unpackhi_epi16(vlo, vhi)); \\\n        }                                                           \\\n        ((__m128i*) o_32)[0] = o_0;                                 \\\n        ((__m128i*) o_32)[1] = o_1;                                 \\\n        ((__m128i*) o_32)[2] = o_2;                                 \\\n        ((__m128i*) o_32)[3] = o_3;                                 \\\n        TR_16(e_32, src, 1, 2 * sstep, SET, end / 2);               \\\n                                                                    \\\n        for (i = 0; i < 16; i++) {                                  \\\n            assign(dst[i * dstep], e_32[i] + o_32[i]);              \\\n            assign(dst[(31 - i) * dstep], e_32[i] - o_32[i]);       \\\n        }                                                           \\\n    } while (0)\n\n#else\n\n#define TR_16(dst, src, dstep, sstep, assign, end)                \\\n    do {                                                          \\\n        int i, j;                                                 \\\n        int e_16[8];                                              \\\n        int o_16[8] = { 0 };                                      \\\n        for (j = 1; j < end; j += 2)                              \\\n            for (i = 0; i < 8; i++)                               \\\n                o_16[i] += transform[2 * j][i] * src[j * sstep];  \\\n        TR_8(e_16, src, 1, 2 * sstep, SET, 8);                    \\\n                                                                  \\\n        for (i = 0; i < 8; i++) {                                 \\\n            assign(dst[i * dstep], e_16[i] + o_16[i]);            \\\n            assign(dst[(15 - i) * dstep], e_16[i] - o_16[i]);     \\\n        }                                                         \\\n    } while (0)\n\n#define TR_32(dst, src, dstep, sstep, assign, end)                \\\n    do {                                                          \\\n        int i, j;                                                 \\\n        int e_32[16];                                             \\\n        int o_32[16] = { 0 };                                     \\\n        for (j = 1; j < end; j += 2)                              \\\n            for (i = 0; i < 16; i++)                              \\\n                o_32[i] += transform[j][i] * src[j * sstep];      \\\n        TR_16(e_32, src, 1, 2 * sstep, SET, end / 2);             \\\n                                                                  \\\n        for (i = 0; i < 16; i++) {                                \\\n            assign(dst[i * dstep], e_32[i] + o_32[i]);            \\\n            assign(dst[(31 - i) * dstep], e_32[i] - o_32[i]);     \\\n        }                                                         \\\n    } while (0)\n\n#endif\n\n#define IDCT_VAR4(H)                                              \\\n    int limit2 = FFMIN(col_limit + 4, H)\n#define IDCT_VAR8(H)                                              \\\n    int limit  = FFMIN(col_limit, H);                             \\\n    int limit2 = FFMIN(col_limit + 4, H)\n#define IDCT_VAR16(H)   IDCT_VAR8(H)\n#define IDCT_VAR32(H)   IDCT_VAR8(H)\n\n#define IDCT(H)                                                   \\\nstatic void FUNC(idct_ ## H ## x ## H )(int16_t *coeffs,          \\\n                                        int col_limit)            \\\n{                                                                 \\\n    int i;                                                        \\\n    int      shift = 7;                                           \\\n    int      add   = 1 << (shift - 1);                            \\\n    int16_t *src   = coeffs;                                      \\\n    IDCT_VAR ## H(H);                                             \\\n                                                                  \\\n    for (i = 0; i < H; i++) {                                     \\\n        TR_ ## H(src, src, H, H, SCALE, limit2);                  \\\n        if (limit2 < H && i%4 == 0 && !!i)                        \\\n            limit2 -= 4;                                          \\\n        src++;                                                    \\\n    }                                                             \\\n                                                                  \\\n    shift = 20 - BIT_DEPTH;                                       \\\n    add   = 1 << (shift - 1);                                     \\\n    for (i = 0; i < H; i++) {                                     \\\n        TR_ ## H(coeffs, coeffs, 1, 1, SCALE, limit);             \\\n        coeffs += H;                                              \\\n    }                                                             \\\n}\n\n#define IDCT_DC(H)                                                \\\nstatic void FUNC(idct_ ## H ## x ## H ## _dc)(int16_t *coeffs)    \\\n{                                                                 \\\n    int i, j;                                                     \\\n    int shift = 14 - BIT_DEPTH;                                   \\\n    int add   = 1 << (shift - 1);                                 \\\n    int coeff = (((coeffs[0] + 1) >> 1) + add) >> shift;          \\\n                                                                  \\\n    for (j = 0; j < H; j++) {                                     \\\n        for (i = 0; i < H; i++) {                                 \\\n            coeffs[i + j * H] = coeff;                            \\\n        }                                                         \\\n    }                                                             \\\n}\n\nIDCT( 4)\nIDCT( 8)\nIDCT(16)\nIDCT(32)\n\nIDCT_DC( 4)\nIDCT_DC( 8)\nIDCT_DC(16)\nIDCT_DC(32)\n\n#undef TR_4\n#undef TR_8\n#undef TR_16\n#undef TR_32\n\n#undef SET\n#undef SCALE\n\nstatic void FUNC(sao_band_filter)(uint8_t *_dst, uint8_t *_src,\n                                  ptrdiff_t stride_dst, ptrdiff_t stride_src,\n                                  int16_t *sao_offset_val, int sao_left_class,\n                                  int width, int height)\n{\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int offset_table[32] = { 0 };\n    int k, y, x;\n    int shift  = BIT_DEPTH - 5;\n\n    stride_dst /= sizeof(pixel);\n    stride_src /= sizeof(pixel);\n\n    for (k = 0; k < 4; k++)\n        offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1];\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(src[x] + offset_table[src[x] >> shift]);\n        dst += stride_dst;\n        src += stride_src;\n    }\n}\n\n#define CMP(a, b) (((a) > (b)) - ((a) < (b)))\n\nstatic void FUNC(sao_edge_filter)(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val,\n                                  int eo, int width, int height) {\n\n    static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 };\n    static const int8_t pos[4][2][2] = {\n        { { -1,  0 }, {  1, 0 } }, // horizontal\n        { {  0, -1 }, {  0, 1 } }, // vertical\n        { { -1, -1 }, {  1, 1 } }, // 45 degree\n        { {  1, -1 }, { -1, 1 } }, // 135 degree\n    };\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int a_stride, b_stride;\n    int x, y;\n    ptrdiff_t stride_src = (2*MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE) / sizeof(pixel);\n    stride_dst /= sizeof(pixel);\n\n    a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src;\n    b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src;\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            int diff0 = CMP(src[x], src[x + a_stride]);\n            int diff1 = CMP(src[x], src[x + b_stride]);\n            int offset_val        = edge_idx[2 + diff0 + diff1];\n            dst[x] = av_clip_pixel(src[x] + sao_offset_val[offset_val]);\n        }\n        src += stride_src;\n        dst += stride_dst;\n    }\n}\n\nstatic void FUNC(sao_edge_restore_0)(uint8_t *_dst, uint8_t *_src,\n                                    ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao,\n                                    int *borders, int _width, int _height,\n                                    int c_idx, uint8_t *vert_edge,\n                                    uint8_t *horiz_edge, uint8_t *diag_edge)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int16_t *sao_offset_val = sao->offset_val[c_idx];\n    int sao_eo_class    = sao->eo_class[c_idx];\n    int init_x = 0, width = _width, height = _height;\n\n    stride_dst /= sizeof(pixel);\n    stride_src /= sizeof(pixel);\n\n    if (sao_eo_class != SAO_EO_VERT) {\n        if (borders[0]) {\n            int offset_val = sao_offset_val[0];\n            for (y = 0; y < height; y++) {\n                dst[y * stride_dst] = av_clip_pixel(src[y * stride_src] + offset_val);\n            }\n            init_x = 1;\n        }\n        if (borders[2]) {\n            int offset_val = sao_offset_val[0];\n            int offset     = width - 1;\n            for (x = 0; x < height; x++) {\n                dst[x * stride_dst + offset] = av_clip_pixel(src[x * stride_src + offset] + offset_val);\n            }\n            width--;\n        }\n    }\n    if (sao_eo_class != SAO_EO_HORIZ) {\n        if (borders[1]) {\n            int offset_val = sao_offset_val[0];\n            for (x = init_x; x < width; x++)\n                dst[x] = av_clip_pixel(src[x] + offset_val);\n        }\n        if (borders[3]) {\n            int offset_val   = sao_offset_val[0];\n            ptrdiff_t y_stride_dst = stride_dst * (height - 1);\n            ptrdiff_t y_stride_src = stride_src * (height - 1);\n            for (x = init_x; x < width; x++)\n                dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + offset_val);\n            height--;\n        }\n    }\n}\n\nstatic void FUNC(sao_edge_restore_1)(uint8_t *_dst, uint8_t *_src,\n                                    ptrdiff_t stride_dst, ptrdiff_t stride_src, SAOParams *sao,\n                                    int *borders, int _width, int _height,\n                                    int c_idx, uint8_t *vert_edge,\n                                    uint8_t *horiz_edge, uint8_t *diag_edge)\n{\n    int x, y;\n    pixel *dst = (pixel *)_dst;\n    pixel *src = (pixel *)_src;\n    int16_t *sao_offset_val = sao->offset_val[c_idx];\n    int sao_eo_class    = sao->eo_class[c_idx];\n    int init_x = 0, init_y = 0, width = _width, height = _height;\n\n    stride_dst /= sizeof(pixel);\n    stride_src /= sizeof(pixel);\n\n    if (sao_eo_class != SAO_EO_VERT) {\n        if (borders[0]) {\n            int offset_val = sao_offset_val[0];\n            for (y = 0; y < height; y++) {\n                dst[y * stride_dst] = av_clip_pixel(src[y * stride_src] + offset_val);\n            }\n            init_x = 1;\n        }\n        if (borders[2]) {\n            int offset_val = sao_offset_val[0];\n            int offset     = width - 1;\n            for (x = 0; x < height; x++) {\n                dst[x * stride_dst + offset] = av_clip_pixel(src[x * stride_src + offset] + offset_val);\n            }\n            width--;\n        }\n    }\n    if (sao_eo_class != SAO_EO_HORIZ) {\n        if (borders[1]) {\n            int offset_val = sao_offset_val[0];\n            for (x = init_x; x < width; x++)\n                dst[x] = av_clip_pixel(src[x] + offset_val);\n            init_y = 1;\n        }\n        if (borders[3]) {\n            int offset_val   = sao_offset_val[0];\n            ptrdiff_t y_stride_dst = stride_dst * (height - 1);\n            ptrdiff_t y_stride_src = stride_src * (height - 1);\n            for (x = init_x; x < width; x++)\n                dst[x + y_stride_dst] = av_clip_pixel(src[x + y_stride_src] + offset_val);\n            height--;\n        }\n    }\n\n    {\n        int save_upper_left  = !diag_edge[0] && sao_eo_class == SAO_EO_135D && !borders[0] && !borders[1];\n        int save_upper_right = !diag_edge[1] && sao_eo_class == SAO_EO_45D  && !borders[1] && !borders[2];\n        int save_lower_right = !diag_edge[2] && sao_eo_class == SAO_EO_135D && !borders[2] && !borders[3];\n        int save_lower_left  = !diag_edge[3] && sao_eo_class == SAO_EO_45D  && !borders[0] && !borders[3];\n\n        // Restore pixels that can't be modified\n        if(vert_edge[0] && sao_eo_class != SAO_EO_VERT) {\n            for(y = init_y+save_upper_left; y< height-save_lower_left; y++)\n                dst[y*stride_dst] = src[y*stride_src];\n        }\n        if(vert_edge[1] && sao_eo_class != SAO_EO_VERT) {\n            for(y = init_y+save_upper_right; y< height-save_lower_right; y++)\n                dst[y*stride_dst+width-1] = src[y*stride_src+width-1];\n        }\n\n        if(horiz_edge[0] && sao_eo_class != SAO_EO_HORIZ) {\n            for(x = init_x+save_upper_left; x < width-save_upper_right; x++)\n                dst[x] = src[x];\n        }\n        if(horiz_edge[1] && sao_eo_class != SAO_EO_HORIZ) {\n            for(x = init_x+save_lower_left; x < width-save_lower_right; x++)\n                dst[(height-1)*stride_dst+x] = src[(height-1)*stride_src+x];\n        }\n        if(diag_edge[0] && sao_eo_class == SAO_EO_135D)\n            dst[0] = src[0];\n        if(diag_edge[1] && sao_eo_class == SAO_EO_45D)\n            dst[width-1] = src[width-1];\n        if(diag_edge[2] && sao_eo_class == SAO_EO_135D)\n            dst[stride_dst*(height-1)+width-1] = src[stride_src*(height-1)+width-1];\n        if(diag_edge[3] && sao_eo_class == SAO_EO_45D)\n            dst[stride_dst*(height-1)] = src[stride_src*(height-1)];\n\n    }\n}\n\n#undef CMP\n\n////////////////////////////////////////////////////////////////////////////////\n//\n////////////////////////////////////////////////////////////////////////////////\nstatic void FUNC(put_hevc_pel_pixels)(int16_t *dst,\n                                      uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = src[x] << (14 - BIT_DEPTH);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_uni_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                          int height, intptr_t mx, intptr_t my, int width)\n{\n    int y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    for (y = 0; y < height; y++) {\n        memcpy(dst, src, width * sizeof(pixel));\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_bi_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                         int16_t *src2,\n                                         int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14  + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((src[x] << (14 - BIT_DEPTH)) + src2[x] + offset) >> shift);\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_uni_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                            int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((src[x] << (14 - BIT_DEPTH)) * wx + offset) >> shift) + ox);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_pel_bi_w_pixels)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                           int16_t *src2,\n                                           int height, int denom, int wx0, int wx1,\n                                           int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src          = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14  + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift;\n\n    int bias = ((ox0 + ox1) * (1 << (BIT_DEPTH - 8)) + 1) << (log2Wd - 1);\n    wx1 <<= (14 - BIT_DEPTH);\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel(( src[x] * wx1 + src2[x] * wx0 + bias) >> log2Wd);\n        }\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//\n////////////////////////////////////////////////////////////////////////////////\n\n#define QPEL_FILTER_0(src, stride) \\\n    (-1 * src[x - 3 * stride] +    \\\n    4 * src[x - 2 * stride] +      \\\n    -10 * src[x - stride] +        \\\n    58 * src[x] +                  \\\n    17 * src[x + stride] +         \\\n    -5 * src[x + 2 * stride] +     \\\n    1 * src[x + 3 * stride])\n\n#define QPEL_FILTER_1(src, stride) \\\n    (-1 * src[x - 3 * stride] +    \\\n    4 * src[x - 2 * stride] +      \\\n    -11 * src[x - stride] +        \\\n    40 * src[x] +                  \\\n    40 * src[x + stride] +         \\\n    -11 * src[x + 2 * stride] +    \\\n    4 * src[x + 3 * stride] +      \\\n    -1 * src[x + 4 * stride])\n\n#define QPEL_FILTER_2(src, stride) \\\n    (1 * src[x - 2 * stride] +     \\\n    -5 * src[x - stride] +         \\\n    17 * src[x] +                  \\\n    58 * src[x + stride] +         \\\n    -10 * src[x + 2 * stride] +    \\\n    4 * src[x + 3 * stride] +      \\\n    -1 * src[x + 4 * stride])\n\n#define QPEL_MACRO_DISPATCH(idx, macro)           \\\n    if ((idx) < 1) { macro(QPEL_FILTER_0) }       \\\n    else if ((idx) == 1) { macro(QPEL_FILTER_1) } \\\n    else { macro(QPEL_FILTER_2) }\n\n\nstatic void FUNC(put_hevc_qpel_h)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height; y++) {                              \\\n        for (x = 0; x < width; x++)                             \\\n            dst[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                       \\\n        dst += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_v)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n\n#define QPEL_BODY(QPEL_FILTER)                                          \\\n    for (y = 0; y < height; y++)  {                                     \\\n        for (x = 0; x < width; x++)                                     \\\n            dst[x] = QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                               \\\n        dst += MAX_PB_SIZE;                                             \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_hv)(int16_t *dst,\n                                   uint8_t *_src,\n                                   ptrdiff_t _srcstride,\n                                   int height, intptr_t mx,\n                                   intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height + QPEL_EXTRA; y++) {                 \\\n        for (x = 0; x < width; x++)                             \\\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                       \\\n        tmp += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height; y++) {                              \\\n        for (x = 0; x < width; x++)                             \\\n            dst[x] = QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6;        \\\n        tmp += MAX_PB_SIZE;                                     \\\n        dst += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_uni_h)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                      uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = 14 - BIT_DEPTH;\n\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n#define QPEL_BODY(QPEL_FILTER)                                                                      \\\n    for (y = 0; y < height; y++) {                                                                  \\\n        for (x = 0; x < width; x++)                                                                 \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + offset) >> shift);   \\\n        src += srcstride;                                                                           \\\n        dst += dststride;                                                                           \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14  + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n#define QPEL_BODY(QPEL_FILTER)                                                                              \\\n    for (y = 0; y < height; y++) {                                                                          \\\n        for (x = 0; x < width; x++)                                                                         \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift); \\\n        src  += srcstride;                                                                                  \\\n        dst  += dststride;                                                                                  \\\n        src2 += MAX_PB_SIZE;                                                                                \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_uni_v)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                     uint8_t *_src, ptrdiff_t _srcstride,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = 14 - BIT_DEPTH;\n\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n#define QPEL_BODY(QPEL_FILTER)                                                                              \\\n    for (y = 0; y < height; y++) {                                                                          \\\n        for (x = 0; x < width; x++)                                                                         \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + offset) >> shift);   \\\n        src += srcstride;                                                                                   \\\n        dst += dststride;                                                                                   \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\n\nstatic void FUNC(put_hevc_qpel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n#define QPEL_BODY(QPEL_FILTER)                                                                                      \\\n    for (y = 0; y < height; y++) {                                                                                  \\\n        for (x = 0; x < width; x++)                                                                                 \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift); \\\n        src  += srcstride;                                                                                          \\\n        dst  += dststride;                                                                                          \\\n        src2 += MAX_PB_SIZE;                                                                                        \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_uni_hv)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                       uint8_t *_src, ptrdiff_t _srcstride,\n                                       int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift =  14 - BIT_DEPTH;\n\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height + QPEL_EXTRA; y++) {                 \\\n        for (x = 0; x < width; x++)                             \\\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                       \\\n        tmp += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n\n#define QPEL_BODY(QPEL_FILTER)                                                                  \\\n    for (y = 0; y < height; y++) {                                                              \\\n        for (x = 0; x < width; x++)                                                             \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + offset) >> shift);   \\\n        tmp += MAX_PB_SIZE;                                                                     \\\n        dst += dststride;                                                                       \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int16_t *src2,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height + QPEL_EXTRA; y++) {                 \\\n        for (x = 0; x < width; x++)                             \\\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                       \\\n        tmp += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n\n#define QPEL_BODY(QPEL_FILTER)                                                                          \\\n    for (y = 0; y < height; y++) {                                                                      \\\n        for (x = 0; x < width; x++)                                                                     \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift); \\\n        tmp  += MAX_PB_SIZE;                                                                            \\\n        dst  += dststride;                                                                              \\\n        src2 += MAX_PB_SIZE;                                                                            \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_uni_w_h)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                        uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox,\n                                        intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox = ox * (1 << (BIT_DEPTH - 8));\n#define QPEL_BODY(QPEL_FILTER)                                                                                  \\\n    for (y = 0; y < height; y++) {                                                                              \\\n        for (x = 0; x < width; x++)                                                                             \\\n            dst[x] = av_clip_pixel((((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);   \\\n        src += srcstride;                                                                                       \\\n        dst += dststride;                                                                                       \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14  + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n#define QPEL_BODY(QPEL_FILTER)                                                                          \\\n    for (y = 0; y < height; y++) {                                                                      \\\n        for (x = 0; x < width; x++)                                                                     \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +    \\\n                                    ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));                \\\n        src  += srcstride;                                                                              \\\n        dst  += dststride;                                                                              \\\n        src2 += MAX_PB_SIZE;                                                                            \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_uni_w_v)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                        uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox,\n                                        intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox = ox * (1 << (BIT_DEPTH - 8));\n#define QPEL_BODY(QPEL_FILTER)                                                                                          \\\n    for (y = 0; y < height; y++) {                                                                                      \\\n        for (x = 0; x < width; x++)                                                                                     \\\n            dst[x] = av_clip_pixel((((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);   \\\n        src += srcstride;                                                                                               \\\n        dst += dststride;                                                                                               \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel        *src       = (pixel*)_src;\n    ptrdiff_t     srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n#define QPEL_BODY(QPEL_FILTER)                                                                                  \\\n    for (y = 0; y < height; y++) {                                                                              \\\n        for (x = 0; x < width; x++)                                                                             \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +    \\\n                                    ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));                        \\\n        src  += srcstride;                                                                                      \\\n        dst  += dststride;                                                                                      \\\n        src2 += MAX_PB_SIZE;                                                                                    \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_uni_w_hv)(uint8_t *_dst,  ptrdiff_t _dststride,\n                                         uint8_t *_src, ptrdiff_t _srcstride,\n                                         int height, int denom, int wx, int ox,\n                                         intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height + QPEL_EXTRA; y++) {                 \\\n        for (x = 0; x < width; x++)                             \\\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                       \\\n        tmp += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n\n    ox = ox * (1 << (BIT_DEPTH - 8));\n\n#define QPEL_BODY(QPEL_FILTER)                                                                              \\\n    for (y = 0; y < height; y++) {                                                                          \\\n        for (x = 0; x < width; x++)                                                                         \\\n            dst[x] = av_clip_pixel((((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx + offset) >> shift) + ox);   \\\n        tmp += MAX_PB_SIZE;                                                                                 \\\n        dst += dststride;                                                                                   \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\nstatic void FUNC(put_hevc_qpel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int16_t *src2,\n                                        int height, int denom, int wx0, int wx1,\n                                        int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel*)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int16_t tmp_array[(MAX_PB_SIZE + QPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    src   -= QPEL_EXTRA_BEFORE * srcstride;\n#define QPEL_BODY(QPEL_FILTER)                                  \\\n    for (y = 0; y < height + QPEL_EXTRA; y++) {                 \\\n        for (x = 0; x < width; x++)                             \\\n            tmp[x] = QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);    \\\n        src += srcstride;                                       \\\n        tmp += MAX_PB_SIZE;                                     \\\n    }\n\n    QPEL_MACRO_DISPATCH(mx - 1, QPEL_BODY)\n#undef QPEL_BODY\n\n    tmp    = tmp_array + QPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n#define QPEL_BODY(QPEL_FILTER)                                                                      \\\n    for (y = 0; y < height; y++) {                                                                  \\\n        for (x = 0; x < width; x++)                                                                 \\\n            dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 +    \\\n                                    ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));            \\\n        tmp  += MAX_PB_SIZE;                                                                        \\\n        dst  += dststride;                                                                          \\\n        src2 += MAX_PB_SIZE;                                                                        \\\n    }\n\n    QPEL_MACRO_DISPATCH(my - 1, QPEL_BODY)\n#undef QPEL_BODY\n}\n\n////////////////////////////////////////////////////////////////////////////////\n//\n////////////////////////////////////////////////////////////////////////////////\n#define EPEL_FILTER(src, stride)                                               \\\n    (filter[0] * src[x - stride] +                                             \\\n     filter[1] * src[x]          +                                             \\\n     filter[2] * src[x + stride] +                                             \\\n     filter[3] * src[x + 2 * stride])\n\nstatic void FUNC(put_hevc_epel_h)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_v)(int16_t *dst,\n                                  uint8_t *_src, ptrdiff_t _srcstride,\n                                  int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_hv)(int16_t *dst,\n                                   uint8_t *_src, ptrdiff_t _srcstride,\n                                   int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6;\n        tmp += MAX_PB_SIZE;\n        dst += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + offset) >> shift);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);\n        }\n        dst  += dststride;\n        src  += srcstride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    int shift = 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + offset) >> shift);\n        src += srcstride;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                     int16_t *src2,\n                                     int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) + src2[x] + offset) >> shift);\n        dst  += dststride;\n        src  += srcstride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + offset) >> shift);\n        tmp += MAX_PB_SIZE;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                      int16_t *src2,\n                                      int height, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) + src2[x] + offset) >> shift);\n        tmp  += MAX_PB_SIZE;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel((((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);\n        }\n        dst += dststride;\n        src += srcstride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++) {\n            dst[x] = av_clip_pixel((((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx + offset) >> shift) + ox);\n        }\n        dst += dststride;\n        src += srcstride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                       int16_t *src2,\n                                       int height, int denom, int wx0, int wx1,\n                                       int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride  = _srcstride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[my - 1];\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));\n        src  += srcstride;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_uni_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                         int height, int denom, int wx, int ox, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = denom + 14 - BIT_DEPTH;\n#if BIT_DEPTH < 14\n    int offset = 1 << (shift - 1);\n#else\n    int offset = 0;\n#endif\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    ox     = ox * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel((((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx + offset) >> shift) + ox);\n        tmp += MAX_PB_SIZE;\n        dst += dststride;\n    }\n}\n\nstatic void FUNC(put_hevc_epel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uint8_t *_src, ptrdiff_t _srcstride,\n                                        int16_t *src2,\n                                        int height, int denom, int wx0, int wx1,\n                                        int ox0, int ox1, intptr_t mx, intptr_t my, int width)\n{\n    int x, y;\n    pixel *src = (pixel *)_src;\n    ptrdiff_t srcstride = _srcstride / sizeof(pixel);\n    pixel *dst          = (pixel *)_dst;\n    ptrdiff_t dststride = _dststride / sizeof(pixel);\n    const int8_t *filter = ff_hevc_epel_filters[mx - 1];\n    int16_t tmp_array[(MAX_PB_SIZE + EPEL_EXTRA) * MAX_PB_SIZE];\n    int16_t *tmp = tmp_array;\n    int shift = 14 + 1 - BIT_DEPTH;\n    int log2Wd = denom + shift - 1;\n\n    src -= EPEL_EXTRA_BEFORE * srcstride;\n\n    for (y = 0; y < height + EPEL_EXTRA; y++) {\n        for (x = 0; x < width; x++)\n            tmp[x] = EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8);\n        src += srcstride;\n        tmp += MAX_PB_SIZE;\n    }\n\n    tmp      = tmp_array + EPEL_EXTRA_BEFORE * MAX_PB_SIZE;\n    filter = ff_hevc_epel_filters[my - 1];\n\n    ox0     = ox0 * (1 << (BIT_DEPTH - 8));\n    ox1     = ox1 * (1 << (BIT_DEPTH - 8));\n    for (y = 0; y < height; y++) {\n        for (x = 0; x < width; x++)\n            dst[x] = av_clip_pixel(((EPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 +\n                                    ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1));\n        tmp  += MAX_PB_SIZE;\n        dst  += dststride;\n        src2 += MAX_PB_SIZE;\n    }\n}\n\n// line zero\n#define P3 pix[-4 * xstride]\n#define P2 pix[-3 * xstride]\n#define P1 pix[-2 * xstride]\n#define P0 pix[-1 * xstride]\n#define Q0 pix[0 * xstride]\n#define Q1 pix[1 * xstride]\n#define Q2 pix[2 * xstride]\n#define Q3 pix[3 * xstride]\n\n// line three. used only for deblocking decision\n#define TP3 pix[-4 * xstride + 3 * ystride]\n#define TP2 pix[-3 * xstride + 3 * ystride]\n#define TP1 pix[-2 * xstride + 3 * ystride]\n#define TP0 pix[-1 * xstride + 3 * ystride]\n#define TQ0 pix[0  * xstride + 3 * ystride]\n#define TQ1 pix[1  * xstride + 3 * ystride]\n#define TQ2 pix[2  * xstride + 3 * ystride]\n#define TQ3 pix[3  * xstride + 3 * ystride]\n\nstatic void FUNC(hevc_loop_filter_luma)(uint8_t *_pix,\n                                        ptrdiff_t _xstride, ptrdiff_t _ystride,\n                                        int beta, int *_tc,\n                                        uint8_t *_no_p, uint8_t *_no_q)\n{\n    int d, j;\n    pixel *pix        = (pixel *)_pix;\n    ptrdiff_t xstride = _xstride / sizeof(pixel);\n    ptrdiff_t ystride = _ystride / sizeof(pixel);\n\n    beta <<= BIT_DEPTH - 8;\n\n    for (j = 0; j < 2; j++) {\n        const int dp0  = abs(P2  - 2 * P1  + P0);\n        const int dq0  = abs(Q2  - 2 * Q1  + Q0);\n        const int dp3  = abs(TP2 - 2 * TP1 + TP0);\n        const int dq3  = abs(TQ2 - 2 * TQ1 + TQ0);\n        const int d0   = dp0 + dq0;\n        const int d3   = dp3 + dq3;\n        const int tc   = _tc[j]   << (BIT_DEPTH - 8);\n        const int no_p = _no_p[j];\n        const int no_q = _no_q[j];\n\n        if (d0 + d3 >= beta) {\n            pix += 4 * ystride;\n            continue;\n        } else {\n            const int beta_3 = beta >> 3;\n            const int beta_2 = beta >> 2;\n            const int tc25   = ((tc * 5 + 1) >> 1);\n\n            if (abs(P3  -  P0) + abs(Q3  -  Q0) < beta_3 && abs(P0  -  Q0) < tc25 &&\n                abs(TP3 - TP0) + abs(TQ3 - TQ0) < beta_3 && abs(TP0 - TQ0) < tc25 &&\n                                      (d0 << 1) < beta_2 &&      (d3 << 1) < beta_2) {\n                // strong filtering\n                const int tc2 = tc << 1;\n                for (d = 0; d < 4; d++) {\n                    const int p3 = P3;\n                    const int p2 = P2;\n                    const int p1 = P1;\n                    const int p0 = P0;\n                    const int q0 = Q0;\n                    const int q1 = Q1;\n                    const int q2 = Q2;\n                    const int q3 = Q3;\n                    if (!no_p) {\n                        P0 = p0 + av_clip(((p2 + 2 * p1 + 2 * p0 + 2 * q0 + q1 + 4) >> 3) - p0, -tc2, tc2);\n                        P1 = p1 + av_clip(((p2 + p1 + p0 + q0 + 2) >> 2) - p1, -tc2, tc2);\n                        P2 = p2 + av_clip(((2 * p3 + 3 * p2 + p1 + p0 + q0 + 4) >> 3) - p2, -tc2, tc2);\n                    }\n                    if (!no_q) {\n                        Q0 = q0 + av_clip(((p1 + 2 * p0 + 2 * q0 + 2 * q1 + q2 + 4) >> 3) - q0, -tc2, tc2);\n                        Q1 = q1 + av_clip(((p0 + q0 + q1 + q2 + 2) >> 2) - q1, -tc2, tc2);\n                        Q2 = q2 + av_clip(((2 * q3 + 3 * q2 + q1 + q0 + p0 + 4) >> 3) - q2, -tc2, tc2);\n                    }\n                    pix += ystride;\n                }\n            } else { // normal filtering\n                int nd_p = 1;\n                int nd_q = 1;\n                const int tc_2 = tc >> 1;\n                if (dp0 + dp3 < ((beta + (beta >> 1)) >> 3))\n                    nd_p = 2;\n                if (dq0 + dq3 < ((beta + (beta >> 1)) >> 3))\n                    nd_q = 2;\n\n                for (d = 0; d < 4; d++) {\n                    const int p2 = P2;\n                    const int p1 = P1;\n                    const int p0 = P0;\n                    const int q0 = Q0;\n                    const int q1 = Q1;\n                    const int q2 = Q2;\n                    int delta0   = (9 * (q0 - p0) - 3 * (q1 - p1) + 8) >> 4;\n                    if (abs(delta0) < 10 * tc) {\n                        delta0 = av_clip(delta0, -tc, tc);\n                        if (!no_p)\n                            P0 = av_clip_pixel(p0 + delta0);\n                        if (!no_q)\n                            Q0 = av_clip_pixel(q0 - delta0);\n                        if (!no_p && nd_p > 1) {\n                            const int deltap1 = av_clip((((p2 + p0 + 1) >> 1) - p1 + delta0) >> 1, -tc_2, tc_2);\n                            P1 = av_clip_pixel(p1 + deltap1);\n                        }\n                        if (!no_q && nd_q > 1) {\n                            const int deltaq1 = av_clip((((q2 + q0 + 1) >> 1) - q1 - delta0) >> 1, -tc_2, tc_2);\n                            Q1 = av_clip_pixel(q1 + deltaq1);\n                        }\n                    }\n                    pix += ystride;\n                }\n            }\n        }\n    }\n}\n\nstatic void FUNC(hevc_loop_filter_chroma)(uint8_t *_pix, ptrdiff_t _xstride,\n                                          ptrdiff_t _ystride, int *_tc,\n                                          uint8_t *_no_p, uint8_t *_no_q)\n{\n    int d, j, no_p, no_q;\n    pixel *pix        = (pixel *)_pix;\n    ptrdiff_t xstride = _xstride / sizeof(pixel);\n    ptrdiff_t ystride = _ystride / sizeof(pixel);\n\n    for (j = 0; j < 2; j++) {\n        const int tc = _tc[j] << (BIT_DEPTH - 8);\n        if (tc <= 0) {\n            pix += 4 * ystride;\n            continue;\n        }\n        no_p = _no_p[j];\n        no_q = _no_q[j];\n\n        for (d = 0; d < 4; d++) {\n            int delta0;\n            const int p1 = P1;\n            const int p0 = P0;\n            const int q0 = Q0;\n            const int q1 = Q1;\n            delta0 = av_clip((((q0 - p0) * 4) + p1 - q1 + 4) >> 3, -tc, tc);\n            if (!no_p)\n                P0 = av_clip_pixel(p0 + delta0);\n            if (!no_q)\n                Q0 = av_clip_pixel(q0 - delta0);\n            pix += ystride;\n        }\n    }\n}\n\nstatic void FUNC(hevc_h_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,\n                                            int32_t *tc, uint8_t *no_p,\n                                            uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_chroma)(pix, stride, sizeof(pixel), tc, no_p, no_q);\n}\n\nstatic void FUNC(hevc_v_loop_filter_chroma)(uint8_t *pix, ptrdiff_t stride,\n                                            int32_t *tc, uint8_t *no_p,\n                                            uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_chroma)(pix, sizeof(pixel), stride, tc, no_p, no_q);\n}\n\nstatic void FUNC(hevc_h_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,\n                                          int beta, int32_t *tc, uint8_t *no_p,\n                                          uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_luma)(pix, stride, sizeof(pixel),\n                                beta, tc, no_p, no_q);\n}\n\nstatic void FUNC(hevc_v_loop_filter_luma)(uint8_t *pix, ptrdiff_t stride,\n                                          int beta, int32_t *tc, uint8_t *no_p,\n                                          uint8_t *no_q)\n{\n    FUNC(hevc_loop_filter_luma)(pix, sizeof(pixel), stride,\n                                beta, tc, no_p, no_q);\n}\n\n#undef P3\n#undef P2\n#undef P1\n#undef P0\n#undef Q0\n#undef Q1\n#undef Q2\n#undef Q3\n\n#undef TP3\n#undef TP2\n#undef TP1\n#undef TP0\n#undef TQ0\n#undef TQ1\n#undef TQ2\n#undef TQ3\n"
  },
  {
    "path": "getYoutubeCombined.py",
    "content": "import sys, platform, socket, re\nimport os, json, requests, subprocess, importlib\n\nsys.stdout = LoggerStream()\nsys.stderr = LoggerStream()\n\npy_version = f\"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}\"\n\n# 64bit / 32bit\narch = platform.architecture()[0]\n\nSTATE_FILE = f\"YoutubeCombined_packages-{py_version}-{arch}.json\"\n\ndef _load_state():\n    return json.load(open(STATE_FILE)) if os.path.exists(STATE_FILE) else {}\n\ndef _save_state(state):\n    json.dump(state, open(STATE_FILE, \"w\"))\n\ndef install_and_import(package, url=None):\n    importlib.invalidate_caches()\n    state = _load_state()\n    if url is None:\n        url = package\n\n    prev = state.get(url, {})\n    headers = {}\n    if prev.get(\"etag\"):\n        headers[\"If-None-Match\"] = prev[\"etag\"]\n    if prev.get(\"last_modified\"):\n        headers[\"If-Modified-Since\"] = prev[\"last_modified\"]\n\n    # HEAD\n    try:\n        r = requests.head(url, allow_redirects=True, timeout=10, headers=headers)\n    except Exception as e:\n        print(f\"[WARN] HEAD failed for {url}: {e}\")\n        r = None\n\n    need_install = False\n    reason = \"initial install\"\n\n    if r:\n        if r.status_code == 304:\n            need_install = False\n            reason = \"304 Not Modified\"\n        else:\n            etag = r.headers.get(\"ETag\")\n            last_modified = r.headers.get(\"Last-Modified\")\n            size = r.headers.get(\"Content-Length\")\n\n            if etag and etag == prev.get(\"etag\"):\n                need_install = False\n                reason = \"ETag match\"\n            elif last_modified and last_modified == prev.get(\"last_modified\"):\n                need_install = False\n                reason = \"Last-Modified match\"\n            elif size and size == prev.get(\"size\"):\n                need_install = False\n                reason = \"Content-Length match\"\n            else:\n                need_install = True\n                reason = \"metadata changed\"\n\n    try:\n        importlib.import_module(package)\n        if need_install:\n            raise ImportError(\"force reinstall\")\n        print(f\"[INFO] {package} already up-to-date ({reason})\")\n    except ImportError:\n        print(f\"[INFO] Installing {package} from {url} ({reason})...\")\n        library_dir = os.path.dirname(os.path.abspath(socket.__file__))\n        pip_path = os.path.join(library_dir, \"../scripts/pip3\")\n\n        cmd = [pip_path, \"install\", \"--force-reinstall\", url]\n\n        result = subprocess.run(cmd, capture_output=True, text=True, check=True)\n        print(\"[INFO] pip output:\\n\", result.stdout)\n\n        for line in result.stdout.splitlines():\n            if \"Installing collected packages\" in line or \"Successfully installed\" in line:\n                print(\"[INFO] Dependencies updated:\", line)\n\n        if r:\n            state[url] = {\n                \"etag\": r.headers.get(\"ETag\"),\n                \"last_modified\": r.headers.get(\"Last-Modified\"),\n                \"size\": r.headers.get(\"Content-Length\"),\n            }\n            _save_state(state)\n\n    globals()[package] = importlib.import_module(package)\n\n# ---- yt-dlp based getYoutubeUrl ----\ninstall_and_import(\"yt_dlp\", \"https://github.com/yt-dlp/yt-dlp/archive/refs/heads/master.zip\")\n\nfrom urllib.parse import urlencode, urlparse, parse_qs\n\ndef parsePlaylist(url: str, force: bool):\n    # 1. Detect search query (no dots or slashes)\n    if all(ch not in url for ch in \"./\"):\n        parts = url.split()\n        query = \"+\".join(urlencode({\"q\": p})[2:] for p in parts)\n        search_url = f\"ytsearch50:{query}\"\n        return _extract_flat_urls(search_url)\n\n    # 2. URL case\n    parsed = urlparse(url)\n    qs = parse_qs(parsed.query)\n\n    is_list = \"list\" in qs\n    is_channel = _is_channel_url(url)\n\n    # Playlist or channel -> treat as list\n    if is_list or is_channel:\n        return _extract_flat_urls(url)\n\n    # 3. Single video page\n    if force:\n        return _extract_from_video_page(url)\n\n    return []\n\n\ndef _is_channel_url(url: str):\n    \"\"\"Detects YouTube channel URLs but does NOT treat them as results.\"\"\"\n    return any(part in url for part in [\n        \"/channel/\",\n        \"/user/\",\n        \"/c/\",\n        \"/@\"\n    ])\n\n\ndef _extract_flat_urls(yt_url: str):\n    ydl_opts = {\n        \"quiet\": True,\n        \"skip_download\": True,\n        \"extract_flat\": True,\n    }\n\n    with yt_dlp.YoutubeDL(ydl_opts) as ydl:\n        info = ydl.extract_info(yt_url, download=False)\n\n    entries = info.get(\"entries\", [])\n    urls = []\n\n    for e in entries:\n        if \"url\" in e:\n            # Filter out channel URLs\n            if not _is_channel_url(e[\"url\"]):\n                urls.append(e[\"url\"])\n\n    return urls\n\n\ndef _extract_from_video_page(video_url: str):\n    ydl_opts = {\n        \"quiet\": True,\n        \"skip_download\": True,\n        \"extract_flat\": False,\n    }\n\n    with yt_dlp.YoutubeDL(ydl_opts) as ydl:\n        info = ydl.extract_info(video_url, download=False)\n\n    urls = []\n\n    # The video itself\n    if \"webpage_url\" in info:\n        urls.append(info[\"webpage_url\"])\n\n    # Playlist URLs (if video is inside a playlist)\n    for pl in info.get(\"playlists\", []):\n        if \"id\" in pl:\n            urls.append(f\"https://www.youtube.com/playlist?list={pl['id']}\")\n\n    # Try to approximate \"related videos\" using search\n    title = info.get(\"title\")\n    if title:\n        search_query = f\"ytsearch10:{title}\"\n        with yt_dlp.YoutubeDL({\"quiet\": True, \"extract_flat\": True}) as ydl:\n            s = ydl.extract_info(search_query, download=False)\n            for e in s.get(\"entries\", []):\n                if \"url\" in e and not _is_channel_url(e[\"url\"]):\n                    urls.append(e[\"url\"])\n\n    # Deduplicate\n    urls = list(dict.fromkeys(urls))\n\n    return urls\n\n\ndef _iter_formats(info):\n    if not info:\n        return []\n    if isinstance(info, dict) and 'entries' in info and info['entries']:\n        for e in info['entries']:\n            if e:\n                info = e\n                break\n    if isinstance(info, dict) and 'requested_formats' in info and info['requested_formats']:\n        return info['requested_formats']\n    if isinstance(info, dict) and 'formats' in info and info['formats']:\n        return info['formats']\n    if isinstance(info, dict) and 'url' in info:\n        return [info]\n    return []\n\ndef _is_usable_video_format(f):\n    vcodec = f.get('vcodec')\n    proto = f.get('protocol', '')\n    if not vcodec or vcodec == 'none':\n        return False\n    if vcodec.startswith('av01'):\n        return False\n    if proto == 'm3u8_native' or proto == 'm3u8':\n        return False\n    return True\n\ndef _is_usable_audio_format(f):\n    vcodec = f.get('vcodec', 'none')\n    proto = f.get('protocol', '')\n    if vcodec != 'none':\n        return False\n    if proto == 'm3u8_native' or proto == 'm3u8':\n        return False\n    return 'audio_channels' in f and f.get('audio_channels') is not None or 'abr' in f\n\ndef getYoutubeUrl(url, adaptive):\n    socket.setdefaulttimeout(10)\n    base_opts = {\n        'noplaylist': True,\n        'quiet': True,\n        'skip_download': True,\n    }\n    ydl_opts = base_opts.copy()\n    ydl_opts['format'] = 'bestvideo+bestaudio' if adaptive else 'best'\n    with yt_dlp.YoutubeDL(ydl_opts) as ydl:\n        info = ydl.extract_info(url, download=False)\n    formats = _iter_formats(info)\n    if adaptive:\n        video_candidates = [f for f in formats if _is_usable_video_format(f)]\n        if video_candidates:\n            best_video = max(video_candidates, key=lambda f: (f.get('height') or 0, f.get('tbr') or 0))\n            video_url = best_video.get('url')\n        else:\n            video_url = info.get('url')\n        audio_candidates = [f for f in formats if _is_usable_audio_format(f)]\n        if audio_candidates:\n            best_audio = max(audio_candidates, key=lambda f: (f.get('audio_channels') or 0, f.get('abr') or 0))\n            audio_url = best_audio.get('url')\n        else:\n            any_audio = next((f for f in formats if f.get('vcodec') == 'none' and f.get('url')), None)\n            audio_url = any_audio.get('url') if any_audio else None\n        return (video_url, audio_url)\n    combined_candidates = [f for f in formats if f.get('vcodec') != 'none' and f.get('audio_channels') is not None and not f.get('vcodec','').startswith('av01') and f.get('protocol') not in ('m3u8_native', 'm3u8')]\n    if not combined_candidates:\n        combined_candidates = [f for f in formats if 'url' in f]\n    best_combined = max(combined_candidates, key=lambda f: (f.get('height') or 0, f.get('tbr') or 0, f.get('abr') or 0))\n    return best_combined.get('url')\n\n# ---- youtube_transcript_api based getYoutubeTranscript ----\ninstall_and_import(\"youtube_transcript_api\", \"https://github.com/jdepoix/youtube-transcript-api/archive/master.zip\")\n\n_YT_ID_RE = re.compile(\n    r'(?:v=|\\/v\\/|youtu\\.be\\/|\\/embed\\/|\\/shorts\\/|watch\\?.*v=)([A-Za-z0-9_-]{11})'\n)\n\ndef extract_youtube_id(url_or_id: str) -> str:\n    if not isinstance(url_or_id, str):\n        raise ValueError(\"video id or url must be a string\")\n    url_or_id = url_or_id.strip()\n    if len(url_or_id) == 11 and re.fullmatch(r'[A-Za-z0-9_-]{11}', url_or_id):\n        return url_or_id\n    m = _YT_ID_RE.search(url_or_id)\n    if m:\n        return m.group(1)\n    q = re.search(r'[?&]v=([A-Za-z0-9_-]{11})', url_or_id)\n    if q:\n        return q.group(1)\n    raise ValueError(\"Could not extract YouTube video id from input\")\n\ndef getYoutubeTranscript(url_or_id: str):\n    video_id = extract_youtube_id(url_or_id)\n    return youtube_transcript_api.YouTubeTranscriptApi().fetch(video_id).to_raw_data()\n"
  },
  {
    "path": "networking/ReadMe.txt",
    "content": "========================================================================\n    STATIC LIBRARY : unzip Project Overview\n========================================================================\n\nAppWizard has created this unzip library project for you.\n\nNo source files were created as part of your project.\n\n\nunzip.vcxproj\n    This is the main project file for VC++ projects generated using an Application Wizard.\n    It contains information about the version of Visual C++ that generated the file, and\n    information about the platforms, configurations, and project features selected with the\n    Application Wizard.\n\nunzip.vcxproj.filters\n    This is the filters file for VC++ projects generated using an Application Wizard. \n    It contains information about the association between the files in your project \n    and the filters. This association is used in the IDE to show grouping of files with\n    similar extensions under a specific node (for e.g. \".cpp\" files are associated with the\n    \"Source Files\" filter).\n\n/////////////////////////////////////////////////////////////////////////////\nOther notes:\n\nAppWizard uses \"TODO:\" comments to indicate parts of the source code you\nshould add to or customize.\n\n/////////////////////////////////////////////////////////////////////////////\n"
  },
  {
    "path": "networking/crypt.h",
    "content": "/* crypt.h -- base code for crypt/uncrypt ZIPfile\n\n\n   Version 1.01e, February 12th, 2005\n\n   Copyright (C) 1998-2005 Gilles Vollant\n\n   This code is a modified version of crypting code in Infozip distribution\n\n   The encryption/decryption parts of this source code (as opposed to the\n   non-echoing password parts) were originally written in Europe.  The\n   whole source package can be freely distributed, including from the USA.\n   (Prior to January 2000, re-export from the US was a violation of US law.)\n\n   This encryption code is a direct transcription of the algorithm from\n   Roger Schlafly, described by Phil Katz in the file appnote.txt.  This\n   file (appnote.txt) is distributed with the PKZIP program (even in the\n   version without encryption capabilities).\n\n   If you don't need crypting in your application, just define symbols\n   NOCRYPT and NOUNCRYPT.\n\n   This code support the \"Traditional PKWARE Encryption\".\n\n   The new AES encryption added on Zip format by Winzip (see the page\n   http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong\n   Encryption is not supported.\n*/\n\n\n#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))\n\n/***********************************************************************\n * Return the next byte in the pseudo-random sequence\n */\nstatic int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab )\n{\n\t//(void) pcrc_32_tab; /* avoid \"unused parameter\" warning */\n\tunsigned temp;  /* POTENTIAL BUG:  temp*(temp^1) may overflow in an\n                     * unpredictable manner on 16-bit systems; not a problem\n                     * with any known compiler so far, though */\n\n\ttemp = ((unsigned)(*(pkeys + 2)) & 0xffff) | 2;\n\treturn (int)(((temp * (temp ^ 1)) >> 8) & 0xff);\n}\n\n/***********************************************************************\n * Update the encryption keys with the next byte of plain text\n */\nstatic int update_keys(unsigned long* pkeys, const unsigned long* pcrc_32_tab, int c)\n{\n\t(*(pkeys + 0)) = CRC32((*(pkeys + 0)), c);\n\t(*(pkeys + 1)) += (*(pkeys + 0)) & 0xff;\n\t(*(pkeys + 1)) = (*(pkeys + 1)) * 134775813L + 1;\n\t{\n\t\tregister int keyshift = (int)((*(pkeys + 1)) >> 24);\n\t\t(*(pkeys + 2)) = CRC32((*(pkeys + 2)), keyshift);\n\t}\n\treturn c;\n}\n\n\n/***********************************************************************\n * Initialize the encryption keys and the random header according to\n * the given password.\n */\nstatic void init_keys(const char* passwd, unsigned long* pkeys, const unsigned long* pcrc_32_tab)\n{\n\t*(pkeys + 0) = 305419896L;\n\t*(pkeys + 1) = 591751049L;\n\t*(pkeys + 2) = 878082192L;\n\twhile (*passwd != '\\0')\n\t{\n\t\tupdate_keys(pkeys, pcrc_32_tab, (int)*passwd);\n\t\tpasswd++;\n\t}\n}\n\n#define zdecode(pkeys,pcrc_32_tab,c) \\\n\t(update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))\n\n#define zencode(pkeys,pcrc_32_tab,c,t) \\\n\t(t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))\n\n#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED\n\n#define RAND_HEAD_LEN  12\n/* \"last resort\" source for second part of crypt seed pattern */\n#  ifndef ZCR_SEED2\n#    define ZCR_SEED2 3141592654UL     /* use PI as default pattern */\n#  endif\n\nstatic int crypthead(passwd, buf, bufSize, pkeys, pcrc_32_tab, crcForCrypting)\nconst char* passwd;         /* password string */\nunsigned char* buf;         /* where to write header */\nint bufSize;\nunsigned long* pkeys;\nconst unsigned long* pcrc_32_tab;\nunsigned long crcForCrypting;\n{\n\tint n;                       /* index in random header */\n\tint t;                       /* temporary */\n\tint c;                       /* random byte */\n\tunsigned char header[RAND_HEAD_LEN - 2]; /* random header */\n\tstatic unsigned calls = 0;   /* ensure different random header each time */\n\n\tif (bufSize < RAND_HEAD_LEN)\n\t\treturn 0;\n\n\t/* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the\n\t * output of rand() to get less predictability, since rand() is\n\t * often poorly implemented.\n\t */\n\tif (++calls == 1)\n\t{\n\t\tsrand((unsigned)(time(NULL) ^ ZCR_SEED2));\n\t}\n\tinit_keys(passwd, pkeys, pcrc_32_tab);\n\tfor (n = 0; n < RAND_HEAD_LEN - 2; n++)\n\t{\n\t\tc = (rand() >> 7) & 0xff;\n\t\theader[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);\n\t}\n\t/* Encrypt random header (last two bytes is high word of crc) */\n\tinit_keys(passwd, pkeys, pcrc_32_tab);\n\tfor (n = 0; n < RAND_HEAD_LEN - 2; n++)\n\t{\n\t\tbuf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);\n\t}\n\tbuf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);\n\tbuf[n++] = zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);\n\treturn n;\n}\n\n#endif\n"
  },
  {
    "path": "networking/http_download.cpp",
    "content": "#include \"http_download.h\"\n\n#include <windows.h>\n#include <winhttp.h>\n#include <stdio.h>\n\n#include <memory>\n#include <string>\n#include <type_traits>\n#include <system_error>\n#include <vector>\n#include <fstream>\n\n//#pragma comment(lib, \"Winhttp\")\n\nnamespace {\n\nauto MakeGuard(HINTERNET h)\n{\n    if (!h)\n    {\n        const DWORD errorCode = GetLastError();\n        throw std::system_error(\n            errorCode, std::system_category(), \"HINTERNET object creation failed.\");\n    }\n\n    return std::unique_ptr<std::remove_pointer_t<HINTERNET>, decltype(&WinHttpCloseHandle)>\n        (h, WinHttpCloseHandle);\n}\n\n} // namespace\n\nbool HttpDownload(const TCHAR* url, const TCHAR* path)\n{\n    std::wstring wszUrl(url, url + _tcslen(url));\n    URL_COMPONENTS urlComp{ sizeof(urlComp) };\n\n    // Set required component lengths to non-zero \n    // so that they are cracked.\n    urlComp.dwSchemeLength = (DWORD)-1;\n    urlComp.dwHostNameLength = (DWORD)-1;\n    urlComp.dwUrlPathLength = (DWORD)-1;\n    urlComp.dwExtraInfoLength = (DWORD)-1;\n\n    if (!WinHttpCrackUrl(wszUrl.c_str(), wszUrl.length(), 0, &urlComp))\n    {\n        fprintf(stderr, \"Error %u in WinHttpCrackUrl.\\n\", GetLastError());\n        return false;\n    }\n\n    // Use WinHttpOpen to obtain a session handle.\n    auto hSession = MakeGuard(WinHttpOpen(L\"HttpDownload/1.0\",\n        WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,\n        WINHTTP_NO_PROXY_NAME,\n        WINHTTP_NO_PROXY_BYPASS, 0));\n\n    // Specify an HTTP server.\n    std::wstring szHostName(\n        urlComp.lpszHostName, urlComp.lpszHostName + urlComp.dwHostNameLength);\n\n    auto hConnect = MakeGuard(WinHttpConnect(hSession.get(), szHostName.c_str(),\n            urlComp.nPort, 0));\n\n    // Create an HTTP request handle.\n    auto hRequest = MakeGuard(WinHttpOpenRequest(hConnect.get(), L\"GET\", \n            urlComp.lpszUrlPath,\n            NULL, WINHTTP_NO_REFERER,\n            WINHTTP_DEFAULT_ACCEPT_TYPES,\n            (urlComp.nScheme == INTERNET_SCHEME_HTTPS)? WINHTTP_FLAG_SECURE : 0));\n\n    // Send a request.\n    BOOL bResults = WinHttpSendRequest(hRequest.get(),\n            WINHTTP_NO_ADDITIONAL_HEADERS, 0,\n            WINHTTP_NO_REQUEST_DATA, 0,\n            0, 0);\n\n    // End the request.\n    if (bResults)\n        bResults = WinHttpReceiveResponse(hRequest.get(), NULL);\n\n    // Keep checking for data until there is nothing left.\n    if (bResults)\n    {\n        std::ofstream f(path, std::ofstream::binary);\n        std::vector<char> buf;\n        for (;;)\n        {\n            DWORD dwSize = 0;\n            // Check for available data.\n            if (!WinHttpQueryDataAvailable(hRequest.get(), &dwSize))\n                fprintf(stderr, \"Error %u in WinHttpQueryDataAvailable.\\n\",\n                    GetLastError());\n\n            if (dwSize == 0)\n                break;\n\n            // Allocate space for the buffer.\n            if (buf.size() < dwSize)\n                buf.resize(dwSize);\n\n            DWORD dwDownloaded = 0;\n\n            if (WinHttpReadData(hRequest.get(), buf.data(),\n                dwSize, &dwDownloaded))\n            {\n                f.write(buf.data(), dwDownloaded);\n            }\n            else\n            {\n                fprintf(stderr, \"Error %u in WinHttpReadData.\\n\", GetLastError());\n            }\n        }\n    }\n\n\n    // Report any errors.\n    if (!bResults)\n        fprintf(stderr, \"Error %d has occurred.\\n\", GetLastError());\n\n    return !!bResults;\n}\n"
  },
  {
    "path": "networking/http_download.h",
    "content": "#pragma once\n\n#include <tchar.h>\n\nbool HttpDownload(const TCHAR* url, const TCHAR* path);\n\n"
  },
  {
    "path": "networking/http_get.cpp",
    "content": "#include \"http_get.h\"\n\n#include \"httprequest_h.h\"\n\n#include <ws2tcpip.h>\n\n#include <algorithm>\n\nnamespace {\n\nconst wchar_t USER_AGENT[]\n    = L\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.75 Safari/537.36\";\n\nclass CComUsageScope\n{\n    bool m_bInitialized;\npublic:\n    explicit CComUsageScope(DWORD dwCoInit = COINIT_MULTITHREADED | COINIT_SPEED_OVER_MEMORY)\n    {\n        m_bInitialized = SUCCEEDED(CoInitializeEx(NULL, dwCoInit));\n    }\n    ~CComUsageScope()\n    {\n        if (m_bInitialized)\n            CoUninitialize();\n    }\n};\n\nstd::string resolveHostnameToIP(const std::string& hostname) {\n    addrinfo hints = { 0 }, * res = nullptr;\n    hints.ai_family = AF_INET; // Allow IPv4\n    hints.ai_socktype = SOCK_STREAM;\n    hints.ai_protocol = IPPROTO_TCP;\n\n    if (getaddrinfo(hostname.c_str(), nullptr, &hints, &res) != 0) {\n        return {};\n    }\n\n    char ipStr[INET6_ADDRSTRLEN];\n    void* addr;\n\n    if (res->ai_family == AF_INET) { // IPv4\n        sockaddr_in* sockaddr_ipv4 = reinterpret_cast<sockaddr_in*>(res->ai_addr);\n        addr = &(sockaddr_ipv4->sin_addr);\n    }\n    else if (res->ai_family == AF_INET6) { // IPv6\n        sockaddr_in6* sockaddr_ipv6 = reinterpret_cast<sockaddr_in6*>(res->ai_addr);\n        addr = &(sockaddr_ipv6->sin6_addr);\n    }\n    else {\n        freeaddrinfo(res);\n        return {};\n    }\n\n    inet_ntop(res->ai_family, addr, ipStr, sizeof(ipStr));\n    freeaddrinfo(res);\n\n    return std::string(ipStr);\n}\n\n} // namespace\n\n\nlong HttpGetStatus(std::string& url, bool useHHO)\n{\n    if (useHHO)\n    {\n        auto matchEnd = std::mismatch(url.begin(), url.end(), \"https://\", \n            [](char c1, char c2) { return tolower(c1) == tolower(c2); });\n        if (matchEnd.first == url.end() || *matchEnd.second != '\\0')\n        {\n            useHHO = false;\n        }\n    }\n\n    CComBSTR bstrUrl;\n    CComBSTR bstrHostname;\n\n    if (useHHO)\n    {\n        const auto pos = 8; // Move past \"://\"\n        size_t endPos = url.find_first_of(\":/\", pos);\n        if (endPos != std::string::npos)\n        {\n            std::string hostname = url.substr(pos, endPos - pos);\n            std::string ip = resolveHostnameToIP(hostname);\n            if (!ip.empty()) {\n                bstrUrl = (url.substr(0, pos) + ip + url.substr(endPos)).c_str();\n                bstrHostname = hostname.c_str();\n            }\n            else\n            {\n                useHHO = false;\n            }\n        }\n        else\n        {\n            useHHO = false;\n        }\n    }\n\n    if (!useHHO)\n    {\n        bstrUrl = url.c_str();\n    }\n\n\n    VARIANT varFalse{ VT_BOOL };\n    VARIANT varEmpty{ VT_ERROR };\n    VARIANT varOption{ VT_I4 };\n    varOption.intVal = 0x1000;\n\n    HRESULT result = 0;\n\n    CComPtr<IWinHttpRequest> pIWinHttpRequest;\n\n    CComUsageScope scope;\n\n    if (FAILED(result = pIWinHttpRequest.CoCreateInstance(L\"WinHttp.WinHttpRequest.5.1\", NULL, CLSCTX_INPROC_SERVER)))\n        return result;\n\n    if (FAILED(result = pIWinHttpRequest->Open(CComBSTR(L\"HEAD\"), bstrUrl, varFalse)))\n        return result;\n\n    if (useHHO && FAILED(result = pIWinHttpRequest->SetRequestHeader(CComBSTR(L\"Host\"), bstrHostname)))\n        return result;\n\n    if (FAILED(result = pIWinHttpRequest->SetRequestHeader(CComBSTR(L\"User-Agent\"), CComBSTR(USER_AGENT))))\n        return result;\n\n    if (useHHO && FAILED(result = pIWinHttpRequest->put_Option(WinHttpRequestOption_SslErrorIgnoreFlags, varOption))) // Ignore SSL errors\n        return result;\n\n    if (FAILED(result = pIWinHttpRequest->put_Option(WinHttpRequestOption_EnableRedirects, varFalse)))\n        return result;\n\n    if (SUCCEEDED(result = pIWinHttpRequest->Send(varEmpty)))\n    {\n        pIWinHttpRequest->get_Status(&result);\n        if (result == 302)\n        {\n            CComBSTR locationHeader;\n            if (SUCCEEDED(pIWinHttpRequest->GetResponseHeader(CComBSTR(L\"Location\"), &locationHeader)))\n            {\n                url = CW2A(locationHeader);\n            }\n        }\n    }\n\n    return result;\n}\n\nCComVariant HttpGet(const char * url)\n{\n    VARIANT varFalse{ VT_BOOL };\n    VARIANT varEmpty{ VT_ERROR };\n\n    CComVariant varBody;\n\n    CComPtr<IWinHttpRequest> pIWinHttpRequest;\n\n    CComUsageScope scope;\n\n    if (SUCCEEDED(pIWinHttpRequest.CoCreateInstance(L\"WinHttp.WinHttpRequest.5.1\", NULL, CLSCTX_INPROC_SERVER))\n        && SUCCEEDED(pIWinHttpRequest->Open(CComBSTR(L\"GET\"), CComBSTR(static_cast<const char*>(url)), varFalse))\n        && SUCCEEDED(pIWinHttpRequest->SetRequestHeader(CComBSTR(L\"User-Agent\"), CComBSTR(USER_AGENT)))\n        && SUCCEEDED(pIWinHttpRequest->Send(varEmpty)))\n    {\n        pIWinHttpRequest->get_ResponseBody(&varBody);\n    }\n\n    return varBody;\n}\n"
  },
  {
    "path": "networking/http_get.h",
    "content": "#pragma once\n\n#include <atlcomcli.h>\n#include <string>\n\n// modifies url if it is a redirect\nlong HttpGetStatus(std::string& url, bool useHHO = true);\n\nCComVariant HttpGet(const char* url);\n"
  },
  {
    "path": "networking/httpioapi.cpp",
    "content": "/* ioapi.c -- IO base function header for compress/uncompress .zip\n   files using zlib + zip or unzip API\n\n   Version 1.01e, February 12th, 2005\n\n   Copyright (C) 1998-2005 Gilles Vollant\n\n   Modified to integrate with WinHttpRequest.\n*/\n\n#include <cassert>\n\n#include \"zlib.h\"\n#include \"ioapi.h\"\n\n#include \"httprequest_h.h\"\n\n#include <atlcomcli.h>\n\n\nvoidpf ZCALLBACK qiodevice_open_file_func(\n    voidpf opaque,\n    voidpf filename,\n    int mode)\n{\n    VARIANT varFalse{ VT_BOOL };\n    VARIANT varEmpty{ VT_ERROR };\n\n    CComVariant varStream;\n\n    CComPtr<IWinHttpRequest> pIWinHttpRequest;\n\n    if (SUCCEEDED(pIWinHttpRequest.CoCreateInstance(L\"WinHttp.WinHttpRequest.5.1\", nullptr, CLSCTX_INPROC_SERVER))\n        && SUCCEEDED(pIWinHttpRequest->Open(CComBSTR(L\"GET\"), CComBSTR(static_cast<const char*>(filename)), varFalse))\n        && SUCCEEDED(pIWinHttpRequest->Send(varEmpty))\n        && SUCCEEDED(pIWinHttpRequest->get_ResponseStream(&varStream)))\n    {\n        if (CComQIPtr<IStream> stream = V_UNKNOWN(&varStream))\n        {\n            return stream.Detach();\n        }\n    }\n\n    return nullptr;\n}\n\n\nuLong ZCALLBACK qiodevice_read_file_func(\n    voidpf, // opaque \n    voidpf pf,\n    void* buf,\n    uLong size)\n{\n    auto stream = static_cast<IStream*>(pf);\n    uLong ret = 0;\n    HRESULT hr = stream->Read(buf, size, &ret);\n    return ret;\n}\n\n\nuLong ZCALLBACK qiodevice_write_file_func(\n    voidpf, // opaque\n    voidpf pf,\n    const void* buf,\n    uLong size)\n{\n    auto stream = static_cast<IStream*>(pf);\n    uLong ret = 0;\n    stream->Write(buf, size, &ret);\n    return ret;\n}\n\nuLong ZCALLBACK qiodevice_tell_file_func(\n    voidpf, // opaque\n    voidpf pf)\n{\n    auto stream = static_cast<IStream*>(pf);\n    const LARGE_INTEGER move{};\n    ULARGE_INTEGER libNewPosition{};\n    stream->Seek(move, STREAM_SEEK_CUR, &libNewPosition);\n    return libNewPosition.LowPart;\n}\n\nint ZCALLBACK qiodevice_seek_file_func(\n    voidpf, // opaque\n    voidpf pf,\n    uLong offset,\n    int origin)\n{\n    STREAM_SEEK dwOrigin;\n    LARGE_INTEGER move;\n    switch (origin)\n    {\n    case ZLIB_FILEFUNC_SEEK_CUR:\n        dwOrigin = STREAM_SEEK_CUR;\n        move.QuadPart = (long)offset;\n        break;\n    case ZLIB_FILEFUNC_SEEK_END:\n        dwOrigin = STREAM_SEEK_END;\n        move.QuadPart = (long)offset;\n        break;\n    case ZLIB_FILEFUNC_SEEK_SET:\n        dwOrigin = STREAM_SEEK_SET;\n        move.QuadPart = offset;\n        break;\n    default: return -1;\n    }\n    auto stream = static_cast<IStream*>(pf);\n    ULARGE_INTEGER libNewPosition{};\n    int ret = FAILED(stream->Seek(move, dwOrigin, &libNewPosition));\n    return ret;\n}\n\nint ZCALLBACK qiodevice_close_file_func(\n    voidpf, // opaque\n    voidpf pf)\n{\n    auto stream = static_cast<IStream*>(pf);\n    auto cnt = stream->Release();\n    assert(cnt == 0);\n    return 0;\n}\n\nint ZCALLBACK qiodevice_error_file_func(\n    voidpf, // opaque\n    voidpf //stream\n)\n{\n    return 0;\n}\n\nvoid fill_qiodevice_filefunc(\n    zlib_filefunc_def* pzlib_filefunc_def)\n{\n    pzlib_filefunc_def->zopen_file = qiodevice_open_file_func;\n    pzlib_filefunc_def->zread_file = qiodevice_read_file_func;\n    pzlib_filefunc_def->zwrite_file = qiodevice_write_file_func;\n    pzlib_filefunc_def->ztell_file = qiodevice_tell_file_func;\n    pzlib_filefunc_def->zseek_file = qiodevice_seek_file_func;\n    pzlib_filefunc_def->zclose_file = qiodevice_close_file_func;\n    pzlib_filefunc_def->zerror_file = qiodevice_error_file_func;\n    pzlib_filefunc_def->opaque = nullptr;\n}\n"
  },
  {
    "path": "networking/httprequest_h.h",
    "content": "\n\n/* this ALWAYS GENERATED file contains the definitions for the interfaces */\n\n\n /* File created by MIDL compiler version 8.00.0603 */\n/* at Wed Jun 06 11:59:31 2018\n */\n/* Compiler settings for C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v7.1A\\Include\\httprequest.idl:\n    Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0603 \n    protocol : dce , ms_ext, c_ext, robust\n    error checks: allocation ref bounds_check enum stub_data \n    VC __declspec() decoration level: \n         __declspec(uuid()), __declspec(selectany), __declspec(novtable)\n         DECLSPEC_UUID(), MIDL_INTERFACE()\n*/\n/* @@MIDL_FILE_HEADING(  ) */\n\n#pragma warning( disable: 4049 )  /* more than 64k source lines */\n\n\n/* verify that the <rpcndr.h> version is high enough to compile this file*/\n#ifndef __REQUIRED_RPCNDR_H_VERSION__\n#define __REQUIRED_RPCNDR_H_VERSION__ 475\n#endif\n\n#include \"rpc.h\"\n#include \"rpcndr.h\"\n\n#ifndef __RPCNDR_H_VERSION__\n#error this stub requires an updated version of <rpcndr.h>\n#endif // __RPCNDR_H_VERSION__\n\n\n#ifndef __httprequest_h_h__\n#define __httprequest_h_h__\n\n#if defined(_MSC_VER) && (_MSC_VER >= 1020)\n#pragma once\n#endif\n\n/* Forward Declarations */ \n\n#ifndef __IWinHttpRequest_FWD_DEFINED__\n#define __IWinHttpRequest_FWD_DEFINED__\ntypedef interface IWinHttpRequest IWinHttpRequest;\n\n#endif \t/* __IWinHttpRequest_FWD_DEFINED__ */\n\n\n#ifndef __IWinHttpRequestEvents_FWD_DEFINED__\n#define __IWinHttpRequestEvents_FWD_DEFINED__\ntypedef interface IWinHttpRequestEvents IWinHttpRequestEvents;\n\n#endif \t/* __IWinHttpRequestEvents_FWD_DEFINED__ */\n\n\n#ifndef __WinHttpRequest_FWD_DEFINED__\n#define __WinHttpRequest_FWD_DEFINED__\n\n#ifdef __cplusplus\ntypedef class WinHttpRequest WinHttpRequest;\n#else\ntypedef struct WinHttpRequest WinHttpRequest;\n#endif /* __cplusplus */\n\n#endif \t/* __WinHttpRequest_FWD_DEFINED__ */\n\n\n#ifdef __cplusplus\nextern \"C\"{\n#endif \n\n\n/* interface __MIDL_itf_httprequest_0000_0000 */\n/* [local] */ \n\n//+-------------------------------------------------------------------------\n//\n//  Microsoft Windows HTTP Services (WinHTTP) version 5.1\n//  Copyright (C) Microsoft Corporation. All rights reserved.\n//\n//--------------------------------------------------------------------------\n\n\nextern RPC_IF_HANDLE __MIDL_itf_httprequest_0000_0000_v0_0_c_ifspec;\nextern RPC_IF_HANDLE __MIDL_itf_httprequest_0000_0000_v0_0_s_ifspec;\n\n\n#ifndef __WinHttp_LIBRARY_DEFINED__\n#define __WinHttp_LIBRARY_DEFINED__\n\n/* library WinHttp */\n/* [version][lcid][helpstring][uuid] */ \n\ntypedef /* [public] */ long HTTPREQUEST_PROXY_SETTING;\n\n#define\tHTTPREQUEST_PROXYSETTING_DEFAULT\t( 0 )\n\n#define\tHTTPREQUEST_PROXYSETTING_PRECONFIG\t( 0 )\n\n#define\tHTTPREQUEST_PROXYSETTING_DIRECT\t( 0x1 )\n\n#define\tHTTPREQUEST_PROXYSETTING_PROXY\t( 0x2 )\n\ntypedef /* [public] */ long HTTPREQUEST_SETCREDENTIALS_FLAGS;\n\n#define\tHTTPREQUEST_SETCREDENTIALS_FOR_SERVER\t( 0 )\n\n#define\tHTTPREQUEST_SETCREDENTIALS_FOR_PROXY\t( 0x1 )\n\ntypedef /* [helpstring][uuid] */  DECLSPEC_UUID(\"12782009-FE90-4877-9730-E5E183669B19\") \nenum WinHttpRequestOption\n    {\n        WinHttpRequestOption_UserAgentString\t= 0,\n        WinHttpRequestOption_URL\t= ( WinHttpRequestOption_UserAgentString + 1 ) ,\n        WinHttpRequestOption_URLCodePage\t= ( WinHttpRequestOption_URL + 1 ) ,\n        WinHttpRequestOption_EscapePercentInURL\t= ( WinHttpRequestOption_URLCodePage + 1 ) ,\n        WinHttpRequestOption_SslErrorIgnoreFlags\t= ( WinHttpRequestOption_EscapePercentInURL + 1 ) ,\n        WinHttpRequestOption_SelectCertificate\t= ( WinHttpRequestOption_SslErrorIgnoreFlags + 1 ) ,\n        WinHttpRequestOption_EnableRedirects\t= ( WinHttpRequestOption_SelectCertificate + 1 ) ,\n        WinHttpRequestOption_UrlEscapeDisable\t= ( WinHttpRequestOption_EnableRedirects + 1 ) ,\n        WinHttpRequestOption_UrlEscapeDisableQuery\t= ( WinHttpRequestOption_UrlEscapeDisable + 1 ) ,\n        WinHttpRequestOption_SecureProtocols\t= ( WinHttpRequestOption_UrlEscapeDisableQuery + 1 ) ,\n        WinHttpRequestOption_EnableTracing\t= ( WinHttpRequestOption_SecureProtocols + 1 ) ,\n        WinHttpRequestOption_RevertImpersonationOverSsl\t= ( WinHttpRequestOption_EnableTracing + 1 ) ,\n        WinHttpRequestOption_EnableHttpsToHttpRedirects\t= ( WinHttpRequestOption_RevertImpersonationOverSsl + 1 ) ,\n        WinHttpRequestOption_EnablePassportAuthentication\t= ( WinHttpRequestOption_EnableHttpsToHttpRedirects + 1 ) ,\n        WinHttpRequestOption_MaxAutomaticRedirects\t= ( WinHttpRequestOption_EnablePassportAuthentication + 1 ) ,\n        WinHttpRequestOption_MaxResponseHeaderSize\t= ( WinHttpRequestOption_MaxAutomaticRedirects + 1 ) ,\n        WinHttpRequestOption_MaxResponseDrainSize\t= ( WinHttpRequestOption_MaxResponseHeaderSize + 1 ) ,\n        WinHttpRequestOption_EnableHttp1_1\t= ( WinHttpRequestOption_MaxResponseDrainSize + 1 ) ,\n        WinHttpRequestOption_EnableCertificateRevocationCheck\t= ( WinHttpRequestOption_EnableHttp1_1 + 1 ) ,\n        WinHttpRequestOption_RejectUserpwd\t= ( WinHttpRequestOption_EnableCertificateRevocationCheck + 1 ) \n    } \tWinHttpRequestOption;\n\ntypedef /* [uuid] */  DECLSPEC_UUID(\"9d8a6df8-13de-4b1f-a330-67c719d62514\") \nenum WinHttpRequestAutoLogonPolicy\n    {\n        AutoLogonPolicy_Always\t= 0,\n        AutoLogonPolicy_OnlyIfBypassProxy\t= ( AutoLogonPolicy_Always + 1 ) ,\n        AutoLogonPolicy_Never\t= ( AutoLogonPolicy_OnlyIfBypassProxy + 1 ) \n    } \tWinHttpRequestAutoLogonPolicy;\n\ntypedef /* [uuid] */  DECLSPEC_UUID(\"152a1ca2-55a9-43a3-b187-0605bb886349\") \nenum WinHttpRequestSslErrorFlags\n    {\n        SslErrorFlag_UnknownCA\t= 0x100,\n        SslErrorFlag_CertWrongUsage\t= 0x200,\n        SslErrorFlag_CertCNInvalid\t= 0x1000,\n        SslErrorFlag_CertDateInvalid\t= 0x2000,\n        SslErrorFlag_Ignore_All\t= 0x3300\n    } \tWinHttpRequestSslErrorFlags;\n\ntypedef /* [uuid] */  DECLSPEC_UUID(\"6b2c51c1-a8ea-46bd-b928-c9b76f9f14dd\") \nenum WinHttpRequestSecureProtocols\n    {\n        SecureProtocol_SSL2\t= 0x8,\n        SecureProtocol_SSL3\t= 0x20,\n        SecureProtocol_TLS1\t= 0x80,\n        SecureProtocol_ALL\t= 0xa8\n    } \tWinHttpRequestSecureProtocols;\n\n\nEXTERN_C const IID LIBID_WinHttp;\n\n#ifndef __IWinHttpRequest_INTERFACE_DEFINED__\n#define __IWinHttpRequest_INTERFACE_DEFINED__\n\n/* interface IWinHttpRequest */\n/* [unique][helpstring][nonextensible][oleautomation][dual][uuid][object] */ \n\n\nEXTERN_C const IID IID_IWinHttpRequest;\n\n#if defined(__cplusplus) && !defined(CINTERFACE)\n    \n    MIDL_INTERFACE(\"016fe2ec-b2c8-45f8-b23b-39e53a75396b\")\n    IWinHttpRequest : public IDispatch\n    {\n    public:\n        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetProxy( \n            /* [in] */ HTTPREQUEST_PROXY_SETTING ProxySetting,\n            /* [optional][in] */ VARIANT ProxyServer,\n            /* [optional][in] */ VARIANT BypassList) = 0;\n        \n        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetCredentials( \n            /* [in] */ BSTR UserName,\n            /* [in] */ BSTR Password,\n            /* [in] */ HTTPREQUEST_SETCREDENTIALS_FLAGS Flags) = 0;\n        \n        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Open( \n            /* [in] */ BSTR Method,\n            /* [in] */ BSTR Url,\n            /* [optional][in] */ VARIANT Async) = 0;\n        \n        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetRequestHeader( \n            /* [in] */ BSTR Header,\n            /* [in] */ BSTR Value) = 0;\n        \n        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetResponseHeader( \n            /* [in] */ BSTR Header,\n            /* [retval][out] */ BSTR *Value) = 0;\n        \n        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE GetAllResponseHeaders( \n            /* [retval][out] */ BSTR *Headers) = 0;\n        \n        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Send( \n            /* [optional][in] */ VARIANT Body) = 0;\n        \n        virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_Status( \n            /* [retval][out] */ long *Status) = 0;\n        \n        virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_StatusText( \n            /* [retval][out] */ BSTR *Status) = 0;\n        \n        virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_ResponseText( \n            /* [retval][out] */ BSTR *Body) = 0;\n        \n        virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_ResponseBody( \n            /* [retval][out] */ VARIANT *Body) = 0;\n        \n        virtual /* [helpstring][id][propget] */ HRESULT STDMETHODCALLTYPE get_ResponseStream( \n            /* [retval][out] */ VARIANT *Body) = 0;\n        \n        virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_Option( \n            /* [in] */ WinHttpRequestOption Option,\n            /* [retval][out] */ VARIANT *Value) = 0;\n        \n        virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_Option( \n            /* [in] */ WinHttpRequestOption Option,\n            /* [in] */ VARIANT Value) = 0;\n        \n        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE WaitForResponse( \n            /* [optional][in] */ VARIANT Timeout,\n            /* [retval][out] */ VARIANT_BOOL *Succeeded) = 0;\n        \n        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE Abort( void) = 0;\n        \n        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetTimeouts( \n            /* [in] */ long ResolveTimeout,\n            /* [in] */ long ConnectTimeout,\n            /* [in] */ long SendTimeout,\n            /* [in] */ long ReceiveTimeout) = 0;\n        \n        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetClientCertificate( \n            /* [in] */ BSTR ClientCertificate) = 0;\n        \n        virtual /* [helpstring][id] */ HRESULT STDMETHODCALLTYPE SetAutoLogonPolicy( \n            /* [in] */ WinHttpRequestAutoLogonPolicy AutoLogonPolicy) = 0;\n        \n    };\n    \n    \n#else \t/* C style interface */\n\n    typedef struct IWinHttpRequestVtbl\n    {\n        BEGIN_INTERFACE\n        \n        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( \n            IWinHttpRequest * This,\n            /* [in] */ REFIID riid,\n            /* [annotation][iid_is][out] */ \n            _COM_Outptr_  void **ppvObject);\n        \n        ULONG ( STDMETHODCALLTYPE *AddRef )( \n            IWinHttpRequest * This);\n        \n        ULONG ( STDMETHODCALLTYPE *Release )( \n            IWinHttpRequest * This);\n        \n        HRESULT ( STDMETHODCALLTYPE *GetTypeInfoCount )( \n            IWinHttpRequest * This,\n            /* [out] */ UINT *pctinfo);\n        \n        HRESULT ( STDMETHODCALLTYPE *GetTypeInfo )( \n            IWinHttpRequest * This,\n            /* [in] */ UINT iTInfo,\n            /* [in] */ LCID lcid,\n            /* [out] */ ITypeInfo **ppTInfo);\n        \n        HRESULT ( STDMETHODCALLTYPE *GetIDsOfNames )( \n            IWinHttpRequest * This,\n            /* [in] */ REFIID riid,\n            /* [size_is][in] */ LPOLESTR *rgszNames,\n            /* [range][in] */ UINT cNames,\n            /* [in] */ LCID lcid,\n            /* [size_is][out] */ DISPID *rgDispId);\n        \n        /* [local] */ HRESULT ( STDMETHODCALLTYPE *Invoke )( \n            IWinHttpRequest * This,\n            /* [annotation][in] */ \n            _In_  DISPID dispIdMember,\n            /* [annotation][in] */ \n            _In_  REFIID riid,\n            /* [annotation][in] */ \n            _In_  LCID lcid,\n            /* [annotation][in] */ \n            _In_  WORD wFlags,\n            /* [annotation][out][in] */ \n            _In_  DISPPARAMS *pDispParams,\n            /* [annotation][out] */ \n            _Out_opt_  VARIANT *pVarResult,\n            /* [annotation][out] */ \n            _Out_opt_  EXCEPINFO *pExcepInfo,\n            /* [annotation][out] */ \n            _Out_opt_  UINT *puArgErr);\n        \n        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetProxy )( \n            IWinHttpRequest * This,\n            /* [in] */ HTTPREQUEST_PROXY_SETTING ProxySetting,\n            /* [optional][in] */ VARIANT ProxyServer,\n            /* [optional][in] */ VARIANT BypassList);\n        \n        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetCredentials )( \n            IWinHttpRequest * This,\n            /* [in] */ BSTR UserName,\n            /* [in] */ BSTR Password,\n            /* [in] */ HTTPREQUEST_SETCREDENTIALS_FLAGS Flags);\n        \n        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Open )( \n            IWinHttpRequest * This,\n            /* [in] */ BSTR Method,\n            /* [in] */ BSTR Url,\n            /* [optional][in] */ VARIANT Async);\n        \n        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetRequestHeader )( \n            IWinHttpRequest * This,\n            /* [in] */ BSTR Header,\n            /* [in] */ BSTR Value);\n        \n        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetResponseHeader )( \n            IWinHttpRequest * This,\n            /* [in] */ BSTR Header,\n            /* [retval][out] */ BSTR *Value);\n        \n        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *GetAllResponseHeaders )( \n            IWinHttpRequest * This,\n            /* [retval][out] */ BSTR *Headers);\n        \n        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Send )( \n            IWinHttpRequest * This,\n            /* [optional][in] */ VARIANT Body);\n        \n        /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_Status )( \n            IWinHttpRequest * This,\n            /* [retval][out] */ long *Status);\n        \n        /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_StatusText )( \n            IWinHttpRequest * This,\n            /* [retval][out] */ BSTR *Status);\n        \n        /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_ResponseText )( \n            IWinHttpRequest * This,\n            /* [retval][out] */ BSTR *Body);\n        \n        /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_ResponseBody )( \n            IWinHttpRequest * This,\n            /* [retval][out] */ VARIANT *Body);\n        \n        /* [helpstring][id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_ResponseStream )( \n            IWinHttpRequest * This,\n            /* [retval][out] */ VARIANT *Body);\n        \n        /* [id][propget] */ HRESULT ( STDMETHODCALLTYPE *get_Option )( \n            IWinHttpRequest * This,\n            /* [in] */ WinHttpRequestOption Option,\n            /* [retval][out] */ VARIANT *Value);\n        \n        /* [id][propput] */ HRESULT ( STDMETHODCALLTYPE *put_Option )( \n            IWinHttpRequest * This,\n            /* [in] */ WinHttpRequestOption Option,\n            /* [in] */ VARIANT Value);\n        \n        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *WaitForResponse )( \n            IWinHttpRequest * This,\n            /* [optional][in] */ VARIANT Timeout,\n            /* [retval][out] */ VARIANT_BOOL *Succeeded);\n        \n        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *Abort )( \n            IWinHttpRequest * This);\n        \n        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetTimeouts )( \n            IWinHttpRequest * This,\n            /* [in] */ long ResolveTimeout,\n            /* [in] */ long ConnectTimeout,\n            /* [in] */ long SendTimeout,\n            /* [in] */ long ReceiveTimeout);\n        \n        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetClientCertificate )( \n            IWinHttpRequest * This,\n            /* [in] */ BSTR ClientCertificate);\n        \n        /* [helpstring][id] */ HRESULT ( STDMETHODCALLTYPE *SetAutoLogonPolicy )( \n            IWinHttpRequest * This,\n            /* [in] */ WinHttpRequestAutoLogonPolicy AutoLogonPolicy);\n        \n        END_INTERFACE\n    } IWinHttpRequestVtbl;\n\n    interface IWinHttpRequest\n    {\n        CONST_VTBL struct IWinHttpRequestVtbl *lpVtbl;\n    };\n\n    \n\n#ifdef COBJMACROS\n\n\n#define IWinHttpRequest_QueryInterface(This,riid,ppvObject)\t\\\n    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) \n\n#define IWinHttpRequest_AddRef(This)\t\\\n    ( (This)->lpVtbl -> AddRef(This) ) \n\n#define IWinHttpRequest_Release(This)\t\\\n    ( (This)->lpVtbl -> Release(This) ) \n\n\n#define IWinHttpRequest_GetTypeInfoCount(This,pctinfo)\t\\\n    ( (This)->lpVtbl -> GetTypeInfoCount(This,pctinfo) ) \n\n#define IWinHttpRequest_GetTypeInfo(This,iTInfo,lcid,ppTInfo)\t\\\n    ( (This)->lpVtbl -> GetTypeInfo(This,iTInfo,lcid,ppTInfo) ) \n\n#define IWinHttpRequest_GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId)\t\\\n    ( (This)->lpVtbl -> GetIDsOfNames(This,riid,rgszNames,cNames,lcid,rgDispId) ) \n\n#define IWinHttpRequest_Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr)\t\\\n    ( (This)->lpVtbl -> Invoke(This,dispIdMember,riid,lcid,wFlags,pDispParams,pVarResult,pExcepInfo,puArgErr) ) \n\n\n#define IWinHttpRequest_SetProxy(This,ProxySetting,ProxyServer,BypassList)\t\\\n    ( (This)->lpVtbl -> SetProxy(This,ProxySetting,ProxyServer,BypassList) ) \n\n#define IWinHttpRequest_SetCredentials(This,UserName,Password,Flags)\t\\\n    ( (This)->lpVtbl -> SetCredentials(This,UserName,Password,Flags) ) \n\n#define IWinHttpRequest_Open(This,Method,Url,Async)\t\\\n    ( (This)->lpVtbl -> Open(This,Method,Url,Async) ) \n\n#define IWinHttpRequest_SetRequestHeader(This,Header,Value)\t\\\n    ( (This)->lpVtbl -> SetRequestHeader(This,Header,Value) ) \n\n#define IWinHttpRequest_GetResponseHeader(This,Header,Value)\t\\\n    ( (This)->lpVtbl -> GetResponseHeader(This,Header,Value) ) \n\n#define IWinHttpRequest_GetAllResponseHeaders(This,Headers)\t\\\n    ( (This)->lpVtbl -> GetAllResponseHeaders(This,Headers) ) \n\n#define IWinHttpRequest_Send(This,Body)\t\\\n    ( (This)->lpVtbl -> Send(This,Body) ) \n\n#define IWinHttpRequest_get_Status(This,Status)\t\\\n    ( (This)->lpVtbl -> get_Status(This,Status) ) \n\n#define IWinHttpRequest_get_StatusText(This,Status)\t\\\n    ( (This)->lpVtbl -> get_StatusText(This,Status) ) \n\n#define IWinHttpRequest_get_ResponseText(This,Body)\t\\\n    ( (This)->lpVtbl -> get_ResponseText(This,Body) ) \n\n#define IWinHttpRequest_get_ResponseBody(This,Body)\t\\\n    ( (This)->lpVtbl -> get_ResponseBody(This,Body) ) \n\n#define IWinHttpRequest_get_ResponseStream(This,Body)\t\\\n    ( (This)->lpVtbl -> get_ResponseStream(This,Body) ) \n\n#define IWinHttpRequest_get_Option(This,Option,Value)\t\\\n    ( (This)->lpVtbl -> get_Option(This,Option,Value) ) \n\n#define IWinHttpRequest_put_Option(This,Option,Value)\t\\\n    ( (This)->lpVtbl -> put_Option(This,Option,Value) ) \n\n#define IWinHttpRequest_WaitForResponse(This,Timeout,Succeeded)\t\\\n    ( (This)->lpVtbl -> WaitForResponse(This,Timeout,Succeeded) ) \n\n#define IWinHttpRequest_Abort(This)\t\\\n    ( (This)->lpVtbl -> Abort(This) ) \n\n#define IWinHttpRequest_SetTimeouts(This,ResolveTimeout,ConnectTimeout,SendTimeout,ReceiveTimeout)\t\\\n    ( (This)->lpVtbl -> SetTimeouts(This,ResolveTimeout,ConnectTimeout,SendTimeout,ReceiveTimeout) ) \n\n#define IWinHttpRequest_SetClientCertificate(This,ClientCertificate)\t\\\n    ( (This)->lpVtbl -> SetClientCertificate(This,ClientCertificate) ) \n\n#define IWinHttpRequest_SetAutoLogonPolicy(This,AutoLogonPolicy)\t\\\n    ( (This)->lpVtbl -> SetAutoLogonPolicy(This,AutoLogonPolicy) ) \n\n#endif /* COBJMACROS */\n\n\n#endif \t/* C style interface */\n\n\n\n\n#endif \t/* __IWinHttpRequest_INTERFACE_DEFINED__ */\n\n\n#ifndef __IWinHttpRequestEvents_INTERFACE_DEFINED__\n#define __IWinHttpRequestEvents_INTERFACE_DEFINED__\n\n/* interface IWinHttpRequestEvents */\n/* [unique][helpstring][nonextensible][oleautomation][uuid][object] */ \n\n\nEXTERN_C const IID IID_IWinHttpRequestEvents;\n\n#if defined(__cplusplus) && !defined(CINTERFACE)\n    \n    MIDL_INTERFACE(\"f97f4e15-b787-4212-80d1-d380cbbf982e\")\n    IWinHttpRequestEvents : public IUnknown\n    {\n    public:\n        virtual void STDMETHODCALLTYPE OnResponseStart( \n            /* [in] */ long Status,\n            /* [in] */ BSTR ContentType) = 0;\n        \n        virtual void STDMETHODCALLTYPE OnResponseDataAvailable( \n            /* [in] */ SAFEARRAY * *Data) = 0;\n        \n        virtual void STDMETHODCALLTYPE OnResponseFinished( void) = 0;\n        \n        virtual void STDMETHODCALLTYPE OnError( \n            /* [in] */ long ErrorNumber,\n            /* [in] */ BSTR ErrorDescription) = 0;\n        \n    };\n    \n    \n#else \t/* C style interface */\n\n    typedef struct IWinHttpRequestEventsVtbl\n    {\n        BEGIN_INTERFACE\n        \n        HRESULT ( STDMETHODCALLTYPE *QueryInterface )( \n            IWinHttpRequestEvents * This,\n            /* [in] */ REFIID riid,\n            /* [annotation][iid_is][out] */ \n            _COM_Outptr_  void **ppvObject);\n        \n        ULONG ( STDMETHODCALLTYPE *AddRef )( \n            IWinHttpRequestEvents * This);\n        \n        ULONG ( STDMETHODCALLTYPE *Release )( \n            IWinHttpRequestEvents * This);\n        \n        void ( STDMETHODCALLTYPE *OnResponseStart )( \n            IWinHttpRequestEvents * This,\n            /* [in] */ long Status,\n            /* [in] */ BSTR ContentType);\n        \n        void ( STDMETHODCALLTYPE *OnResponseDataAvailable )( \n            IWinHttpRequestEvents * This,\n            /* [in] */ SAFEARRAY * *Data);\n        \n        void ( STDMETHODCALLTYPE *OnResponseFinished )( \n            IWinHttpRequestEvents * This);\n        \n        void ( STDMETHODCALLTYPE *OnError )( \n            IWinHttpRequestEvents * This,\n            /* [in] */ long ErrorNumber,\n            /* [in] */ BSTR ErrorDescription);\n        \n        END_INTERFACE\n    } IWinHttpRequestEventsVtbl;\n\n    interface IWinHttpRequestEvents\n    {\n        CONST_VTBL struct IWinHttpRequestEventsVtbl *lpVtbl;\n    };\n\n    \n\n#ifdef COBJMACROS\n\n\n#define IWinHttpRequestEvents_QueryInterface(This,riid,ppvObject)\t\\\n    ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) ) \n\n#define IWinHttpRequestEvents_AddRef(This)\t\\\n    ( (This)->lpVtbl -> AddRef(This) ) \n\n#define IWinHttpRequestEvents_Release(This)\t\\\n    ( (This)->lpVtbl -> Release(This) ) \n\n\n#define IWinHttpRequestEvents_OnResponseStart(This,Status,ContentType)\t\\\n    ( (This)->lpVtbl -> OnResponseStart(This,Status,ContentType) ) \n\n#define IWinHttpRequestEvents_OnResponseDataAvailable(This,Data)\t\\\n    ( (This)->lpVtbl -> OnResponseDataAvailable(This,Data) ) \n\n#define IWinHttpRequestEvents_OnResponseFinished(This)\t\\\n    ( (This)->lpVtbl -> OnResponseFinished(This) ) \n\n#define IWinHttpRequestEvents_OnError(This,ErrorNumber,ErrorDescription)\t\\\n    ( (This)->lpVtbl -> OnError(This,ErrorNumber,ErrorDescription) ) \n\n#endif /* COBJMACROS */\n\n\n#endif \t/* C style interface */\n\n\n\n\n#endif \t/* __IWinHttpRequestEvents_INTERFACE_DEFINED__ */\n\n\nEXTERN_C const CLSID CLSID_WinHttpRequest;\n\n#ifdef __cplusplus\n\nclass DECLSPEC_UUID(\"2087c2f4-2cef-4953-a8ab-66779b670495\")\nWinHttpRequest;\n#endif\n#endif /* __WinHttp_LIBRARY_DEFINED__ */\n\n/* Additional Prototypes for ALL interfaces */\n\n/* end of Additional Prototypes */\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n\n"
  },
  {
    "path": "networking/ioapi.h",
    "content": "/* ioapi.h -- IO base function header for compress/uncompress .zip\n   files using zlib + zip or unzip API\n\n   Version 1.01e, February 12th, 2005\n\n   Copyright (C) 1998-2005 Gilles Vollant\n\n   Modified to integrate with WinHttpRequest.\n*/\n\n#ifndef _ZLIBIOAPI_H\n#define _ZLIBIOAPI_H\n\n\n#define ZLIB_FILEFUNC_SEEK_CUR (1)\n#define ZLIB_FILEFUNC_SEEK_END (2)\n#define ZLIB_FILEFUNC_SEEK_SET (0)\n\n#define ZLIB_FILEFUNC_MODE_READ      (1)\n#define ZLIB_FILEFUNC_MODE_WRITE     (2)\n#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)\n\n#define ZLIB_FILEFUNC_MODE_EXISTING (4)\n#define ZLIB_FILEFUNC_MODE_CREATE   (8)\n\n\n#ifndef ZCALLBACK\n\n#if (defined(WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)\n#define ZCALLBACK CALLBACK\n#else\n#define ZCALLBACK\n#endif\n#endif\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n\ttypedef voidpf(ZCALLBACK* open_file_func) OF((voidpf opaque, voidpf file, int mode));\n\ttypedef uLong(ZCALLBACK* read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));\n\ttypedef uLong(ZCALLBACK* write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));\n\ttypedef uLong(ZCALLBACK* tell_file_func) OF((voidpf opaque, voidpf stream));\n\ttypedef int (ZCALLBACK* seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));\n\ttypedef int (ZCALLBACK* close_file_func) OF((voidpf opaque, voidpf stream));\n\ttypedef int (ZCALLBACK* testerror_file_func) OF((voidpf opaque, voidpf stream));\n\n\ttypedef struct zlib_filefunc_def_s\n\t{\n\t\topen_file_func      zopen_file;\n\t\tread_file_func      zread_file;\n\t\twrite_file_func     zwrite_file;\n\t\ttell_file_func      ztell_file;\n\t\tseek_file_func      zseek_file;\n\t\tclose_file_func     zclose_file;\n\t\ttesterror_file_func zerror_file;\n\t\tvoidpf              opaque;\n\t} zlib_filefunc_def;\n\n\n\n\tvoid fill_qiodevice_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));\n\n#define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size))\n#define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size))\n#define ZTELL(filefunc,filestream) ((*((filefunc).ztell_file))((filefunc).opaque,filestream))\n#define ZSEEK(filefunc,filestream,pos,mode) ((*((filefunc).zseek_file))((filefunc).opaque,filestream,pos,mode))\n#define ZCLOSE(filefunc,filestream) ((*((filefunc).zclose_file))((filefunc).opaque,filestream))\n#define ZERROR(filefunc,filestream) ((*((filefunc).zerror_file))((filefunc).opaque,filestream))\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif\n\n"
  },
  {
    "path": "networking/networking.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{3DE6C2D2-FDFC-4745-8282-981DF7561405}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>unzip</RootNamespace>\n    <ProjectName>networking</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <Text Include=\"ReadMe.txt\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"httprequest_i.c\" />\n    <ClCompile Include=\"httpioapi.cpp\" />\n    <ClCompile Include=\"http_download.cpp\" />\n    <ClCompile Include=\"http_get.cpp\" />\n    <ClCompile Include=\"unzip.c\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"crypt.h\" />\n    <ClInclude Include=\"httprequest_h.h\" />\n    <ClInclude Include=\"http_download.h\" />\n    <ClInclude Include=\"http_get.h\" />\n    <ClInclude Include=\"ioapi.h\" />\n    <ClInclude Include=\"unzip.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "networking/networking.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <Text Include=\"ReadMe.txt\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"unzip.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"httprequest_i.c\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"httpioapi.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"http_get.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"http_download.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"crypt.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ioapi.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"unzip.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"httprequest_h.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"http_get.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"http_download.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "networking/unzip.c",
    "content": "/* unzip.c -- IO for uncompress .zip files using zlib\n   Version 1.01e, February 12th, 2005\n\n   Copyright (C) 1998-2005 Gilles Vollant\n\n   Read unzip.h for more info\n\n   Modified to integrate with WinHttpRequest.\n*/\n\n/* Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of\ncompatibility with older software. The following is from the original crypt.c. Code\nwoven in by Terry Thorsen 1/2003.\n*/\n/*\n  Copyright (c) 1990-2000 Info-ZIP.  All rights reserved.\n\n  See the accompanying file LICENSE, version 2000-Apr-09 or later\n  (the contents of which are also included in zip.h) for terms of use.\n  If, for some reason, all these files are missing, the Info-ZIP license\n  also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html\n*/\n/*\n  crypt.c (full version) by Info-ZIP.      Last revised:  [see crypt.h]\n\n  The encryption/decryption parts of this source code (as opposed to the\n  non-echoing password parts) were originally written in Europe.  The\n  whole source package can be freely distributed, including from the USA.\n  (Prior to January 2000, re-export from the US was a violation of US law.)\n */\n\n/*\n  This encryption code is a direct transcription of the algorithm from\n  Roger Schlafly, described by Phil Katz in the file appnote.txt.  This\n  file (appnote.txt) is distributed with the PKZIP program (even in the\n  version without encryption capabilities).\n */\n\n\n#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include \"zlib.h\"\n#include \"unzip.h\"\n\n#ifdef STDC\n#  include <stddef.h>\n#  include <string.h>\n#  include <stdlib.h>\n#endif\n#ifdef NO_ERRNO_H\n    extern int errno;\n#else\n#   include <errno.h>\n#endif\n\n\n#ifndef local\n#  define local static\n#endif\n/* compile with -Dlocal if your debugger can't find static symbols */\n\n\n#ifndef CASESENSITIVITYDEFAULT_NO\n#  if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)\n#    define CASESENSITIVITYDEFAULT_NO\n#  endif\n#endif\n\n\n#ifndef UNZ_BUFSIZE\n#define UNZ_BUFSIZE (16384)\n#endif\n\n#ifndef UNZ_MAXFILENAMEINZIP\n#define UNZ_MAXFILENAMEINZIP (256)\n#endif\n\n#ifndef ALLOC\n# define ALLOC(size) (malloc(size))\n#endif\n#ifndef TRYFREE\n# define TRYFREE(p) {if (p) free(p);}\n#endif\n\n#define SIZECENTRALDIRITEM (0x2e)\n#define SIZEZIPLOCALHEADER (0x1e)\n\n\n\n\nconst char unz_copyright[] =\n   \" unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll\";\n\n/* unz_file_info_interntal contain internal info about a file in zipfile*/\ntypedef struct unz_file_info_internal_s\n{\n    uLong offset_curfile;/* relative offset of local header 4 bytes */\n} unz_file_info_internal;\n\n\n/* file_in_zip_read_info_s contain internal information about a file in zipfile,\n    when reading and decompress it */\ntypedef struct\n{\n    char  *read_buffer;         /* internal buffer for compressed data */\n    z_stream stream;            /* zLib stream structure for inflate */\n\n    uLong pos_in_zipfile;       /* position in byte on the zipfile, for fseek*/\n    uLong stream_initialised;   /* flag set if stream structure is initialised*/\n\n    uLong offset_local_extrafield;/* offset of the local extra field */\n    uInt  size_local_extrafield;/* size of the local extra field */\n    uLong pos_local_extrafield;   /* position in the local extra field in read*/\n\n    uLong crc32;                /* crc32 of all data uncompressed */\n    uLong crc32_wait;           /* crc32 we must obtain after decompress all */\n    uLong rest_read_compressed; /* number of byte to be decompressed */\n    uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/\n    zlib_filefunc_def z_filefunc;\n    voidpf filestream;        /* io structore of the zipfile */\n    uLong compression_method;   /* compression method (0==store) */\n    uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/\n    int   raw;\n} file_in_zip_read_info_s;\n\n\n/* unz_s contain internal information about the zipfile\n*/\ntypedef struct\n{\n    zlib_filefunc_def z_filefunc;\n    voidpf filestream;        /* io structore of the zipfile */\n    unz_global_info gi;       /* public global information */\n    uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/\n    uLong num_file;             /* number of the current file in the zipfile*/\n    uLong pos_in_central_dir;   /* pos of the current file in the central dir*/\n    uLong current_file_ok;      /* flag about the usability of the current file*/\n    uLong central_pos;          /* position of the beginning of the central dir*/\n\n    uLong size_central_dir;     /* size of the central directory  */\n    uLong offset_central_dir;   /* offset of start of central directory with\n                                   respect to the starting disk number */\n\n    unz_file_info cur_file_info; /* public info about the current file in zip*/\n    unz_file_info_internal cur_file_info_internal; /* private info about it*/\n    file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current\n                                        file if we are decompressing it */\n    int encrypted;\n#    ifndef NOUNCRYPT\n    unsigned long keys[3];     /* keys defining the pseudo-random sequence */\n    const unsigned long* pcrc_32_tab;\n#    endif\n} unz_s;\n\n\n#ifndef NOUNCRYPT\n#include \"crypt.h\"\n#endif\n\n/* ===========================================================================\n     Read a byte from a gz_stream; update next_in and avail_in. Return EOF\n   for end of file.\n   IN assertion: the stream s has been sucessfully opened for reading.\n*/\n\n\nlocal int unzlocal_getByte OF((\n    const zlib_filefunc_def* pzlib_filefunc_def,\n    voidpf filestream,\n    int *pi));\n\nlocal int unzlocal_getByte(pzlib_filefunc_def,filestream,pi)\n    const zlib_filefunc_def* pzlib_filefunc_def;\n    voidpf filestream;\n    int *pi;\n{\n    unsigned char c;\n    int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1);\n    if (err==1)\n    {\n        *pi = (int)c;\n        return UNZ_OK;\n    }\n    if (ZERROR(*pzlib_filefunc_def,filestream))\n        return UNZ_ERRNO;\n    return UNZ_EOF;\n}\n\n\n/* ===========================================================================\n   Reads a long in LSB order from the given gz_stream. Sets\n*/\nlocal int unzlocal_getShort OF((\n    const zlib_filefunc_def* pzlib_filefunc_def,\n    voidpf filestream,\n    uLong *pX));\n\nlocal int unzlocal_getShort (pzlib_filefunc_def,filestream,pX)\n    const zlib_filefunc_def* pzlib_filefunc_def;\n    voidpf filestream;\n    uLong *pX;\n{\n    uLong x ;\n    int i;\n    int err;\n\n    err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);\n    x = (uLong)i;\n\n    if (err==UNZ_OK)\n        err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);\n    x += ((uLong)i)<<8;\n\n    if (err==UNZ_OK)\n        *pX = x;\n    else\n        *pX = 0;\n    return err;\n}\n\nlocal int unzlocal_getLong OF((\n    const zlib_filefunc_def* pzlib_filefunc_def,\n    voidpf filestream,\n    uLong *pX));\n\nlocal int unzlocal_getLong (pzlib_filefunc_def,filestream,pX)\n    const zlib_filefunc_def* pzlib_filefunc_def;\n    voidpf filestream;\n    uLong *pX;\n{\n    uLong x ;\n    int i;\n    int err;\n\n    err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);\n    x = (uLong)i;\n\n    if (err==UNZ_OK)\n        err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);\n    x += ((uLong)i)<<8;\n\n    if (err==UNZ_OK)\n        err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);\n    x += ((uLong)i)<<16;\n\n    if (err==UNZ_OK)\n        err = unzlocal_getByte(pzlib_filefunc_def,filestream,&i);\n    x += ((uLong)i)<<24;\n\n    if (err==UNZ_OK)\n        *pX = x;\n    else\n        *pX = 0;\n    return err;\n}\n\n\n/* My own strcmpi / strcasecmp */\nlocal int strcmpcasenosensitive_internal (fileName1,fileName2)\n    const char* fileName1;\n    const char* fileName2;\n{\n    for (;;)\n    {\n        char c1=*(fileName1++);\n        char c2=*(fileName2++);\n        if ((c1>='a') && (c1<='z'))\n            c1 -= 0x20;\n        if ((c2>='a') && (c2<='z'))\n            c2 -= 0x20;\n        if (c1=='\\0')\n            return ((c2=='\\0') ? 0 : -1);\n        if (c2=='\\0')\n            return 1;\n        if (c1<c2)\n            return -1;\n        if (c1>c2)\n            return 1;\n    }\n}\n\n\n#ifdef  CASESENSITIVITYDEFAULT_NO\n#define CASESENSITIVITYDEFAULTVALUE 2\n#else\n#define CASESENSITIVITYDEFAULTVALUE 1\n#endif\n\n#ifndef STRCMPCASENOSENTIVEFUNCTION\n#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal\n#endif\n\n/*\n   Compare two filename (fileName1,fileName2).\n   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)\n   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi\n                                                                or strcasecmp)\n   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system\n        (like 1 on Unix, 2 on Windows)\n\n*/\nextern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity)\n    const char* fileName1;\n    const char* fileName2;\n    int iCaseSensitivity;\n{\n    if (iCaseSensitivity==0)\n        iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;\n\n    if (iCaseSensitivity==1)\n        return strcmp(fileName1,fileName2);\n\n    return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);\n}\n\n#ifndef BUFREADCOMMENT\n#define BUFREADCOMMENT (0x400)\n#endif\n\n/*\n  Locate the Central directory of a zipfile (at the end, just before\n    the global comment)\n*/\nlocal uLong unzlocal_SearchCentralDir OF((\n    const zlib_filefunc_def* pzlib_filefunc_def,\n    voidpf filestream));\n\nlocal uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream)\n    const zlib_filefunc_def* pzlib_filefunc_def;\n    voidpf filestream;\n{\n    unsigned char* buf;\n    uLong uSizeFile;\n    uLong uBackRead;\n    uLong uMaxBack=0xffff; /* maximum size of global comment */\n    uLong uPosFound=0;\n\n    if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)\n        return 0;\n\n\n    uSizeFile = ZTELL(*pzlib_filefunc_def,filestream);\n\n    if (uMaxBack>uSizeFile)\n        uMaxBack = uSizeFile;\n\n    buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);\n    if (buf==NULL)\n        return 0;\n\n    uBackRead = 4;\n    while (uBackRead<uMaxBack)\n    {\n        uLong uReadSize,uReadPos ;\n        int i;\n        if (uBackRead+BUFREADCOMMENT>uMaxBack)\n            uBackRead = uMaxBack;\n        else\n            uBackRead+=BUFREADCOMMENT;\n        uReadPos = uSizeFile-uBackRead ;\n\n        uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?\n                     (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);\n        if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)\n            break;\n\n        if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)\n            break;\n\n        for (i=(int)uReadSize-3; (i--)>0;)\n            if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&\n                ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))\n            {\n                uPosFound = uReadPos+i;\n                break;\n            }\n\n        if (uPosFound!=0)\n            break;\n    }\n    TRYFREE(buf);\n    return uPosFound;\n}\n\n/*\n  Open a Zip file. path contain the full pathname (by example,\n     on a Windows NT computer \"c:\\\\test\\\\zlib114.zip\" or on an Unix computer\n     \"zlib/zlib114.zip\".\n     If the zipfile cannot be opened (file doesn't exist or in not valid), the\n       return value is NULL.\n     Else, the return value is a unzFile Handle, usable with other function\n       of this unzip package.\n*/\nextern unzFile ZEXPORT unzOpen2 (file, pzlib_filefunc_def)\n    voidpf file;\n    zlib_filefunc_def* pzlib_filefunc_def;\n{\n    unz_s us;\n    unz_s *s;\n    uLong central_pos,uL;\n\n    uLong number_disk;          /* number of the current dist, used for\n                                   spaning ZIP, unsupported, always 0*/\n    uLong number_disk_with_CD;  /* number the the disk with central dir, used\n                                   for spaning ZIP, unsupported, always 0*/\n    uLong number_entry_CD;      /* total number of entries in\n                                   the central dir\n                                   (same than number_entry on nospan) */\n\n    int err=UNZ_OK;\n\n    if (unz_copyright[0]!=' ')\n        return NULL;\n\n    if (pzlib_filefunc_def==NULL)\n        fill_qiodevice_filefunc(&us.z_filefunc);\n    else\n        us.z_filefunc = *pzlib_filefunc_def;\n\n    us.filestream= (*(us.z_filefunc.zopen_file))(us.z_filefunc.opaque,\n                                                 file,\n                                                 ZLIB_FILEFUNC_MODE_READ |\n                                                 ZLIB_FILEFUNC_MODE_EXISTING);\n    if (us.filestream==NULL)\n        return NULL;\n\n    central_pos = unzlocal_SearchCentralDir(&us.z_filefunc,us.filestream);\n    if (central_pos==0)\n        err=UNZ_ERRNO;\n\n    if (ZSEEK(us.z_filefunc, us.filestream,\n                                      central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)\n        err=UNZ_ERRNO;\n\n    /* the signature, already checked */\n    if (unzlocal_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)\n        err=UNZ_ERRNO;\n\n    /* number of this disk */\n    if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)\n        err=UNZ_ERRNO;\n\n    /* number of the disk with the start of the central directory */\n    if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)\n        err=UNZ_ERRNO;\n\n    /* total number of entries in the central dir on this disk */\n    if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK)\n        err=UNZ_ERRNO;\n\n    /* total number of entries in the central dir */\n    if (unzlocal_getShort(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if ((number_entry_CD!=us.gi.number_entry) ||\n        (number_disk_with_CD!=0) ||\n        (number_disk!=0))\n        err=UNZ_BADZIPFILE;\n\n    /* size of the central directory */\n    if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK)\n        err=UNZ_ERRNO;\n\n    /* offset of start of central directory with respect to the\n          starting disk number */\n    if (unzlocal_getLong(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK)\n        err=UNZ_ERRNO;\n\n    /* zipfile comment length */\n    if (unzlocal_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if ((central_pos<us.offset_central_dir+us.size_central_dir) &&\n        (err==UNZ_OK))\n        err=UNZ_BADZIPFILE;\n\n    if (err!=UNZ_OK)\n    {\n        ZCLOSE(us.z_filefunc, us.filestream);\n        return NULL;\n    }\n\n    us.byte_before_the_zipfile = central_pos -\n                            (us.offset_central_dir+us.size_central_dir);\n    us.central_pos = central_pos;\n    us.pfile_in_zip_read = NULL;\n    us.encrypted = 0;\n\n\n    s=(unz_s*)ALLOC(sizeof(unz_s));\n    *s=us;\n    unzGoToFirstFile((unzFile)s);\n    return (unzFile)s;\n}\n\n\nextern unzFile ZEXPORT unzOpen (file)\n    voidpf file;\n{\n    return unzOpen2(file, NULL);\n}\n\n/*\n  Close a ZipFile opened with unzipOpen.\n  If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),\n    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.\n  return UNZ_OK if there is no problem. */\nextern int ZEXPORT unzClose (file)\n    unzFile file;\n{\n    unz_s* s;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n\n    if (s->pfile_in_zip_read!=NULL)\n        unzCloseCurrentFile(file);\n\n    ZCLOSE(s->z_filefunc, s->filestream);\n    TRYFREE(s);\n    return UNZ_OK;\n}\n\n\n/*\n  Write info about the ZipFile in the *pglobal_info structure.\n  No preparation of the structure is needed\n  return UNZ_OK if there is no problem. */\nextern int ZEXPORT unzGetGlobalInfo (file,pglobal_info)\n    unzFile file;\n    unz_global_info *pglobal_info;\n{\n    unz_s* s;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n    *pglobal_info=s->gi;\n    return UNZ_OK;\n}\n\n\n/*\n   Translate date/time from Dos format to tm_unz (readable more easilty)\n*/\nlocal void unzlocal_DosDateToTmuDate (ulDosDate, ptm)\n    uLong ulDosDate;\n    tm_unz* ptm;\n{\n    uLong uDate;\n    uDate = (uLong)(ulDosDate>>16);\n    ptm->tm_mday = (uInt)(uDate&0x1f) ;\n    ptm->tm_mon =  (uInt)((((uDate)&0x1E0)/0x20)-1) ;\n    ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;\n\n    ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);\n    ptm->tm_min =  (uInt) ((ulDosDate&0x7E0)/0x20) ;\n    ptm->tm_sec =  (uInt) (2*(ulDosDate&0x1f)) ;\n}\n\n/*\n  Get Info about the current file in the zipfile, with internal only info\n*/\nlocal int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,\n                                                  unz_file_info *pfile_info,\n                                                  unz_file_info_internal\n                                                  *pfile_info_internal,\n                                                  char *szFileName,\n                                                  uLong fileNameBufferSize,\n                                                  void *extraField,\n                                                  uLong extraFieldBufferSize,\n                                                  char *szComment,\n                                                  uLong commentBufferSize));\n\nlocal int unzlocal_GetCurrentFileInfoInternal (file,\n                                              pfile_info,\n                                              pfile_info_internal,\n                                              szFileName, fileNameBufferSize,\n                                              extraField, extraFieldBufferSize,\n                                              szComment,  commentBufferSize)\n    unzFile file;\n    unz_file_info *pfile_info;\n    unz_file_info_internal *pfile_info_internal;\n    char *szFileName;\n    uLong fileNameBufferSize;\n    void *extraField;\n    uLong extraFieldBufferSize;\n    char *szComment;\n    uLong commentBufferSize;\n{\n    unz_s* s;\n    unz_file_info file_info;\n    unz_file_info_internal file_info_internal;\n    int err=UNZ_OK;\n    uLong uMagic;\n    uLong uSeek=0;\n\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n    if (ZSEEK(s->z_filefunc, s->filestream,\n              s->pos_in_central_dir+s->byte_before_the_zipfile,\n              ZLIB_FILEFUNC_SEEK_SET)!=0)\n        err=UNZ_ERRNO;\n\n\n    /* we check the magic */\n    if (err==UNZ_OK) {\n        if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)\n            err=UNZ_ERRNO;\n        else if (uMagic!=0x02014b50)\n            err=UNZ_BADZIPFILE;\n    }\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);\n\n    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    uSeek+=file_info.size_filename;\n    if ((err==UNZ_OK) && (szFileName!=NULL))\n    {\n        uLong uSizeRead ;\n        if (file_info.size_filename<fileNameBufferSize)\n        {\n            *(szFileName+file_info.size_filename)='\\0';\n            uSizeRead = file_info.size_filename;\n        }\n        else\n            uSizeRead = fileNameBufferSize;\n\n        if ((file_info.size_filename>0) && (fileNameBufferSize>0))\n            if (ZREAD(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)\n                err=UNZ_ERRNO;\n        uSeek -= uSizeRead;\n    }\n\n\n    if ((err==UNZ_OK) && (extraField!=NULL))\n    {\n        uLong uSizeRead ;\n        if (file_info.size_file_extra<extraFieldBufferSize)\n            uSizeRead = file_info.size_file_extra;\n        else\n            uSizeRead = extraFieldBufferSize;\n\n        if (uSeek!=0) {\n            if (ZSEEK(s->z_filefunc, s->filestream,uSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)\n                uSeek=0;\n            else\n                err=UNZ_ERRNO;\n        }\n        if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))\n            if (ZREAD(s->z_filefunc, s->filestream,extraField,uSizeRead)!=uSizeRead)\n                err=UNZ_ERRNO;\n        uSeek += file_info.size_file_extra - uSizeRead;\n    }\n    else\n        uSeek+=file_info.size_file_extra;\n\n\n    if ((err==UNZ_OK) && (szComment!=NULL))\n    {\n        uLong uSizeRead ;\n        if (file_info.size_file_comment<commentBufferSize)\n        {\n            *(szComment+file_info.size_file_comment)='\\0';\n            uSizeRead = file_info.size_file_comment;\n        }\n        else\n            uSizeRead = commentBufferSize;\n\n        if (uSeek!=0) {\n            if (ZSEEK(s->z_filefunc, s->filestream,uSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)\n                uSeek=0;\n            else\n                err=UNZ_ERRNO;\n        }\n        if ((file_info.size_file_comment>0) && (commentBufferSize>0))\n            if (ZREAD(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)\n                err=UNZ_ERRNO;\n        uSeek+=file_info.size_file_comment - uSizeRead;\n    }\n    else\n        uSeek+=file_info.size_file_comment;\n\n    if ((err==UNZ_OK) && (pfile_info!=NULL))\n        *pfile_info=file_info;\n\n    if ((err==UNZ_OK) && (pfile_info_internal!=NULL))\n        *pfile_info_internal=file_info_internal;\n\n    return err;\n}\n\n\n\n/*\n  Write info about the ZipFile in the *pglobal_info structure.\n  No preparation of the structure is needed\n  return UNZ_OK if there is no problem.\n*/\nextern int ZEXPORT unzGetCurrentFileInfo (file,\n                                          pfile_info,\n                                          szFileName, fileNameBufferSize,\n                                          extraField, extraFieldBufferSize,\n                                          szComment,  commentBufferSize)\n    unzFile file;\n    unz_file_info *pfile_info;\n    char *szFileName;\n    uLong fileNameBufferSize;\n    void *extraField;\n    uLong extraFieldBufferSize;\n    char *szComment;\n    uLong commentBufferSize;\n{\n    return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,\n                                                szFileName,fileNameBufferSize,\n                                                extraField,extraFieldBufferSize,\n                                                szComment,commentBufferSize);\n}\n\n/*\n  Set the current file of the zipfile to the first file.\n  return UNZ_OK if there is no problem\n*/\nextern int ZEXPORT unzGoToFirstFile (file)\n    unzFile file;\n{\n    int err=UNZ_OK;\n    unz_s* s;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n    s->pos_in_central_dir=s->offset_central_dir;\n    s->num_file=0;\n    err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n                                             &s->cur_file_info_internal,\n                                             NULL,0,NULL,0,NULL,0);\n    s->current_file_ok = (err == UNZ_OK);\n    return err;\n}\n\n/*\n  Set the current file of the zipfile to the next file.\n  return UNZ_OK if there is no problem\n  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.\n*/\nextern int ZEXPORT unzGoToNextFile (file)\n    unzFile file;\n{\n    unz_s* s;\n    int err;\n\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n    if (!s->current_file_ok)\n        return UNZ_END_OF_LIST_OF_FILE;\n    if (s->gi.number_entry != 0xffff)    /* 2^16 files overflow hack */\n      if (s->num_file+1==s->gi.number_entry)\n        return UNZ_END_OF_LIST_OF_FILE;\n\n    s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +\n            s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;\n    s->num_file++;\n    err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n                                               &s->cur_file_info_internal,\n                                               NULL,0,NULL,0,NULL,0);\n    s->current_file_ok = (err == UNZ_OK);\n    return err;\n}\n\n\n/*\n  Try locate the file szFileName in the zipfile.\n  For the iCaseSensitivity signification, see unzipStringFileNameCompare\n\n  return value :\n  UNZ_OK if the file is found. It becomes the current file.\n  UNZ_END_OF_LIST_OF_FILE if the file is not found\n*/\nextern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity)\n    unzFile file;\n    const char *szFileName;\n    int iCaseSensitivity;\n{\n    unz_s* s;\n    int err;\n\n    /* We remember the 'current' position in the file so that we can jump\n     * back there if we fail.\n     */\n    unz_file_info cur_file_infoSaved;\n    unz_file_info_internal cur_file_info_internalSaved;\n    uLong num_fileSaved;\n    uLong pos_in_central_dirSaved;\n\n\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n\n    if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)\n        return UNZ_PARAMERROR;\n\n    s=(unz_s*)file;\n    if (!s->current_file_ok)\n        return UNZ_END_OF_LIST_OF_FILE;\n\n    /* Save the current state */\n    num_fileSaved = s->num_file;\n    pos_in_central_dirSaved = s->pos_in_central_dir;\n    cur_file_infoSaved = s->cur_file_info;\n    cur_file_info_internalSaved = s->cur_file_info_internal;\n\n    err = unzGoToFirstFile(file);\n\n    while (err == UNZ_OK)\n    {\n        char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];\n        err = unzGetCurrentFileInfo(file,NULL,\n                                    szCurrentFileName,sizeof(szCurrentFileName)-1,\n                                    NULL,0,NULL,0);\n        if (err == UNZ_OK)\n        {\n            if (unzStringFileNameCompare(szCurrentFileName,\n                                            szFileName,iCaseSensitivity)==0)\n                return UNZ_OK;\n            err = unzGoToNextFile(file);\n        }\n    }\n\n    /* We failed, so restore the state of the 'current file' to where we\n     * were.\n     */\n    s->num_file = num_fileSaved ;\n    s->pos_in_central_dir = pos_in_central_dirSaved ;\n    s->cur_file_info = cur_file_infoSaved;\n    s->cur_file_info_internal = cur_file_info_internalSaved;\n    return err;\n}\n\n\n/*\n///////////////////////////////////////////\n// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)\n// I need random access\n//\n// Further optimization could be realized by adding an ability\n// to cache the directory in memory. The goal being a single\n// comprehensive file read to put the file I need in a memory.\n*/\n\n/*\ntypedef struct unz_file_pos_s\n{\n    uLong pos_in_zip_directory;   // offset in file\n    uLong num_of_file;            // # of file\n} unz_file_pos;\n*/\n\nextern int ZEXPORT unzGetFilePos(file, file_pos)\n    unzFile file;\n    unz_file_pos* file_pos;\n{\n    unz_s* s;\n\n    if (file==NULL || file_pos==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n    if (!s->current_file_ok)\n        return UNZ_END_OF_LIST_OF_FILE;\n\n    file_pos->pos_in_zip_directory  = s->pos_in_central_dir;\n    file_pos->num_of_file           = s->num_file;\n\n    return UNZ_OK;\n}\n\nextern int ZEXPORT unzGoToFilePos(file, file_pos)\n    unzFile file;\n    unz_file_pos* file_pos;\n{\n    unz_s* s;\n    int err;\n\n    if (file==NULL || file_pos==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n\n    /* jump to the right spot */\n    s->pos_in_central_dir = file_pos->pos_in_zip_directory;\n    s->num_file           = file_pos->num_of_file;\n\n    /* set the current file */\n    err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n                                               &s->cur_file_info_internal,\n                                               NULL,0,NULL,0,NULL,0);\n    /* return results */\n    s->current_file_ok = (err == UNZ_OK);\n    return err;\n}\n\n/*\n// Unzip Helper Functions - should be here?\n///////////////////////////////////////////\n*/\n\n/*\n  Read the local header of the current zipfile\n  Check the coherency of the local header and info in the end of central\n        directory about this file\n  store in *piSizeVar the size of extra info in local header\n        (filename and size of extra field data)\n*/\nlocal int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,\n                                                    poffset_local_extrafield,\n                                                    psize_local_extrafield)\n    unz_s* s;\n    uInt* piSizeVar;\n    uLong *poffset_local_extrafield;\n    uInt  *psize_local_extrafield;\n{\n    uLong uMagic,uData,uFlags;\n    uLong size_filename;\n    uLong size_extra_field;\n    int err=UNZ_OK;\n\n    *piSizeVar = 0;\n    *poffset_local_extrafield = 0;\n    *psize_local_extrafield = 0;\n\n    if (ZSEEK(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile +\n                                s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)\n        return UNZ_ERRNO;\n\n\n    if (err==UNZ_OK) {\n        if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)\n            err=UNZ_ERRNO;\n        else if (uMagic!=0x04034b50)\n            err=UNZ_BADZIPFILE;\n    }\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)\n        err=UNZ_ERRNO;\n/*\n    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))\n        err=UNZ_BADZIPFILE;\n*/\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK)\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)\n        err=UNZ_ERRNO;\n    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))\n        err=UNZ_BADZIPFILE;\n\n    if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&\n                         (s->cur_file_info.compression_method!=Z_DEFLATED))\n        err=UNZ_BADZIPFILE;\n\n    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */\n        err=UNZ_ERRNO;\n\n    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */\n        err=UNZ_ERRNO;\n    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&\n                              ((uFlags & 8)==0))\n        err=UNZ_BADZIPFILE;\n\n    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */\n        err=UNZ_ERRNO;\n    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&\n                              ((uFlags & 8)==0))\n        err=UNZ_BADZIPFILE;\n\n    if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */\n        err=UNZ_ERRNO;\n    else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) &&\n                              ((uFlags & 8)==0))\n        err=UNZ_BADZIPFILE;\n\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK)\n        err=UNZ_ERRNO;\n    else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))\n        err=UNZ_BADZIPFILE;\n\n    *piSizeVar += (uInt)size_filename;\n\n    if (unzlocal_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK)\n        err=UNZ_ERRNO;\n    *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +\n                                    SIZEZIPLOCALHEADER + size_filename;\n    *psize_local_extrafield = (uInt)size_extra_field;\n\n    *piSizeVar += (uInt)size_extra_field;\n\n    return err;\n}\n\n/*\n  Open for reading data the current file in the zipfile.\n  If there is no error and the file is opened, the return value is UNZ_OK.\n*/\nextern int ZEXPORT unzOpenCurrentFile3 (file, method, level, raw, password)\n    unzFile file;\n    int* method;\n    int* level;\n    int raw;\n    const char* password;\n{\n    int err=UNZ_OK;\n    uInt iSizeVar;\n    unz_s* s;\n    file_in_zip_read_info_s* pfile_in_zip_read_info;\n    uLong offset_local_extrafield;  /* offset of the local extra field */\n    uInt  size_local_extrafield;    /* size of the local extra field */\n#    ifndef NOUNCRYPT\n    char source[12];\n#    else\n    if (password != NULL)\n        return UNZ_PARAMERROR;\n#    endif\n\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n    if (!s->current_file_ok)\n        return UNZ_PARAMERROR;\n\n    if (s->pfile_in_zip_read != NULL)\n        unzCloseCurrentFile(file);\n\n    if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,\n                &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)\n        return UNZ_BADZIPFILE;\n\n    pfile_in_zip_read_info = (file_in_zip_read_info_s*)\n                                        ALLOC(sizeof(file_in_zip_read_info_s));\n    if (pfile_in_zip_read_info==NULL)\n        return UNZ_INTERNALERROR;\n\n    pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);\n    pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;\n    pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;\n    pfile_in_zip_read_info->pos_local_extrafield=0;\n    pfile_in_zip_read_info->raw=raw;\n\n    if (pfile_in_zip_read_info->read_buffer==NULL)\n    {\n        TRYFREE(pfile_in_zip_read_info);\n        return UNZ_INTERNALERROR;\n    }\n\n    pfile_in_zip_read_info->stream_initialised=0;\n\n    if (method!=NULL)\n        *method = (int)s->cur_file_info.compression_method;\n\n    if (level!=NULL)\n    {\n        *level = 6;\n        switch (s->cur_file_info.flag & 0x06)\n        {\n          case 6 : *level = 1; break;\n          case 4 : *level = 2; break;\n          case 2 : *level = 9; break;\n        }\n    }\n\n    if ((s->cur_file_info.compression_method!=0) &&\n        (s->cur_file_info.compression_method!=Z_DEFLATED))\n        err=UNZ_BADZIPFILE;\n\n    pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;\n    pfile_in_zip_read_info->crc32=0;\n    pfile_in_zip_read_info->compression_method =\n            s->cur_file_info.compression_method;\n    pfile_in_zip_read_info->filestream=s->filestream;\n    pfile_in_zip_read_info->z_filefunc=s->z_filefunc;\n    pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;\n\n    pfile_in_zip_read_info->stream.total_out = 0;\n\n    if ((s->cur_file_info.compression_method==Z_DEFLATED) &&\n        (!raw))\n    {\n      pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;\n      pfile_in_zip_read_info->stream.zfree = (free_func)0;\n      pfile_in_zip_read_info->stream.opaque = (voidpf)0;\n      pfile_in_zip_read_info->stream.next_in = (voidpf)0;\n      pfile_in_zip_read_info->stream.avail_in = 0;\n\n      err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);\n      if (err == Z_OK)\n        pfile_in_zip_read_info->stream_initialised=1;\n      else\n      {\n        TRYFREE(pfile_in_zip_read_info);\n        return err;\n      }\n        /* windowBits is passed < 0 to tell that there is no zlib header.\n         * Note that in this case inflate *requires* an extra \"dummy\" byte\n         * after the compressed stream in order to complete decompression and\n         * return Z_STREAM_END.\n         * In unzip, i don't wait absolutely Z_STREAM_END because I known the\n         * size of both compressed and uncompressed data\n         */\n    }\n    pfile_in_zip_read_info->rest_read_compressed =\n            s->cur_file_info.compressed_size ;\n    pfile_in_zip_read_info->rest_read_uncompressed =\n            s->cur_file_info.uncompressed_size ;\n\n\n    pfile_in_zip_read_info->pos_in_zipfile =\n            s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +\n              iSizeVar;\n\n    pfile_in_zip_read_info->stream.avail_in = (uInt)0;\n\n    s->pfile_in_zip_read = pfile_in_zip_read_info;\n\n#    ifndef NOUNCRYPT\n    if (password != NULL)\n    {\n        int i;\n        s->pcrc_32_tab = get_crc_table();\n        init_keys(password,s->keys,s->pcrc_32_tab);\n        if (ZSEEK(s->z_filefunc, s->filestream,\n                  s->pfile_in_zip_read->pos_in_zipfile +\n                     s->pfile_in_zip_read->byte_before_the_zipfile,\n                  SEEK_SET)!=0)\n            return UNZ_INTERNALERROR;\n        if(ZREAD(s->z_filefunc, s->filestream,source, 12)<12)\n            return UNZ_INTERNALERROR;\n\n        for (i = 0; i<12; i++)\n            zdecode(s->keys,s->pcrc_32_tab,source[i]);\n\n        s->pfile_in_zip_read->pos_in_zipfile+=12;\n        s->encrypted=1;\n    }\n#    endif\n\n\n    return UNZ_OK;\n}\n\nextern int ZEXPORT unzOpenCurrentFile (file)\n    unzFile file;\n{\n    return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);\n}\n\nextern int ZEXPORT unzOpenCurrentFilePassword (file, password)\n    unzFile file;\n    const char* password;\n{\n    return unzOpenCurrentFile3(file, NULL, NULL, 0, password);\n}\n\nextern int ZEXPORT unzOpenCurrentFile2 (file,method,level,raw)\n    unzFile file;\n    int* method;\n    int* level;\n    int raw;\n{\n    return unzOpenCurrentFile3(file, method, level, raw, NULL);\n}\n\n/*\n  Read bytes from the current file.\n  buf contain buffer where data must be copied\n  len the size of buf.\n\n  return the number of byte copied if somes bytes are copied\n  return 0 if the end of file was reached\n  return <0 with error code if there is an error\n    (UNZ_ERRNO for IO error, or zLib error for uncompress error)\n*/\nextern int ZEXPORT unzReadCurrentFile  (file, buf, len)\n    unzFile file;\n    voidp buf;\n    unsigned len;\n{\n    int err=UNZ_OK;\n    uInt iRead = 0;\n    unz_s* s;\n    file_in_zip_read_info_s* pfile_in_zip_read_info;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n    if (pfile_in_zip_read_info==NULL)\n        return UNZ_PARAMERROR;\n\n\n    if (pfile_in_zip_read_info->read_buffer == NULL)\n        return UNZ_END_OF_LIST_OF_FILE;\n    if (len==0)\n        return 0;\n\n    pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;\n\n    pfile_in_zip_read_info->stream.avail_out = (uInt)len;\n\n    if ((len>pfile_in_zip_read_info->rest_read_uncompressed) &&\n        (!(pfile_in_zip_read_info->raw)))\n        pfile_in_zip_read_info->stream.avail_out =\n            (uInt)pfile_in_zip_read_info->rest_read_uncompressed;\n\n    if ((len>pfile_in_zip_read_info->rest_read_compressed+\n           pfile_in_zip_read_info->stream.avail_in) &&\n         (pfile_in_zip_read_info->raw))\n        pfile_in_zip_read_info->stream.avail_out =\n            (uInt)pfile_in_zip_read_info->rest_read_compressed+\n            pfile_in_zip_read_info->stream.avail_in;\n\n    while (pfile_in_zip_read_info->stream.avail_out>0)\n    {\n        if ((pfile_in_zip_read_info->stream.avail_in==0) &&\n            (pfile_in_zip_read_info->rest_read_compressed>0))\n        {\n            uInt uReadThis = UNZ_BUFSIZE;\n            if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)\n                uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;\n            if (uReadThis == 0)\n                return UNZ_EOF;\n            if (ZSEEK(pfile_in_zip_read_info->z_filefunc,\n                      pfile_in_zip_read_info->filestream,\n                      pfile_in_zip_read_info->pos_in_zipfile +\n                         pfile_in_zip_read_info->byte_before_the_zipfile,\n                         ZLIB_FILEFUNC_SEEK_SET)!=0)\n                return UNZ_ERRNO;\n            if (ZREAD(pfile_in_zip_read_info->z_filefunc,\n                      pfile_in_zip_read_info->filestream,\n                      pfile_in_zip_read_info->read_buffer,\n                      uReadThis)!=uReadThis)\n                return UNZ_ERRNO;\n\n\n#            ifndef NOUNCRYPT\n            if(s->encrypted)\n            {\n                uInt i;\n                for(i=0;i<uReadThis;i++)\n                  pfile_in_zip_read_info->read_buffer[i] =\n                      zdecode(s->keys,s->pcrc_32_tab,\n                              pfile_in_zip_read_info->read_buffer[i]);\n            }\n#            endif\n\n\n            pfile_in_zip_read_info->pos_in_zipfile += uReadThis;\n\n            pfile_in_zip_read_info->rest_read_compressed-=uReadThis;\n\n            pfile_in_zip_read_info->stream.next_in =\n                (Bytef*)pfile_in_zip_read_info->read_buffer;\n            pfile_in_zip_read_info->stream.avail_in = uReadThis;\n        }\n\n        if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw))\n        {\n            uInt uDoCopy,i ;\n\n            if ((pfile_in_zip_read_info->stream.avail_in == 0) &&\n                (pfile_in_zip_read_info->rest_read_compressed == 0))\n                return (iRead==0) ? UNZ_EOF : iRead;\n\n            if (pfile_in_zip_read_info->stream.avail_out <\n                            pfile_in_zip_read_info->stream.avail_in)\n                uDoCopy = pfile_in_zip_read_info->stream.avail_out ;\n            else\n                uDoCopy = pfile_in_zip_read_info->stream.avail_in ;\n\n            for (i=0;i<uDoCopy;i++)\n                *(pfile_in_zip_read_info->stream.next_out+i) =\n                        *(pfile_in_zip_read_info->stream.next_in+i);\n\n            pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,\n                                pfile_in_zip_read_info->stream.next_out,\n                                uDoCopy);\n            pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;\n            pfile_in_zip_read_info->stream.avail_in -= uDoCopy;\n            pfile_in_zip_read_info->stream.avail_out -= uDoCopy;\n            pfile_in_zip_read_info->stream.next_out += uDoCopy;\n            pfile_in_zip_read_info->stream.next_in += uDoCopy;\n            pfile_in_zip_read_info->stream.total_out += uDoCopy;\n            iRead += uDoCopy;\n        }\n        else\n        {\n            uLong uTotalOutBefore,uTotalOutAfter;\n            const Bytef *bufBefore;\n            uLong uOutThis;\n            int flush=Z_SYNC_FLUSH;\n\n            uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;\n            bufBefore = pfile_in_zip_read_info->stream.next_out;\n\n            /*\n            if ((pfile_in_zip_read_info->rest_read_uncompressed ==\n                     pfile_in_zip_read_info->stream.avail_out) &&\n                (pfile_in_zip_read_info->rest_read_compressed == 0))\n                flush = Z_FINISH;\n            */\n            err=inflate(&pfile_in_zip_read_info->stream,flush);\n\n            if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL))\n              err = Z_DATA_ERROR;\n\n            uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;\n            uOutThis = uTotalOutAfter-uTotalOutBefore;\n\n            pfile_in_zip_read_info->crc32 =\n                crc32(pfile_in_zip_read_info->crc32,bufBefore,\n                        (uInt)(uOutThis));\n\n            pfile_in_zip_read_info->rest_read_uncompressed -=\n                uOutThis;\n\n            iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);\n\n            if (err==Z_STREAM_END)\n                return (iRead==0) ? UNZ_EOF : iRead;\n            if (err!=Z_OK)\n                break;\n        }\n    }\n\n    if (err==Z_OK)\n        return iRead;\n    return err;\n}\n\n\n/*\n  Give the current position in uncompressed data\n*/\nextern z_off_t ZEXPORT unztell (file)\n    unzFile file;\n{\n    unz_s* s;\n    file_in_zip_read_info_s* pfile_in_zip_read_info;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n    if (pfile_in_zip_read_info==NULL)\n        return UNZ_PARAMERROR;\n\n    return (z_off_t)pfile_in_zip_read_info->stream.total_out;\n}\n\n\n/*\n  return 1 if the end of file was reached, 0 elsewhere\n*/\nextern int ZEXPORT unzeof (file)\n    unzFile file;\n{\n    unz_s* s;\n    file_in_zip_read_info_s* pfile_in_zip_read_info;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n    if (pfile_in_zip_read_info==NULL)\n        return UNZ_PARAMERROR;\n\n    if (pfile_in_zip_read_info->rest_read_uncompressed == 0)\n        return 1;\n    return 0;\n}\n\n\n\n/*\n  Read extra field from the current file (opened by unzOpenCurrentFile)\n  This is the local-header version of the extra field (sometimes, there is\n    more info in the local-header version than in the central-header)\n\n  if buf==NULL, it return the size of the local extra field that can be read\n\n  if buf!=NULL, len is the size of the buffer, the extra header is copied in\n    buf.\n  the return value is the number of bytes copied in buf, or (if <0)\n    the error code\n*/\nextern int ZEXPORT unzGetLocalExtrafield (file,buf,len)\n    unzFile file;\n    voidp buf;\n    unsigned len;\n{\n    unz_s* s;\n    file_in_zip_read_info_s* pfile_in_zip_read_info;\n    uInt read_now;\n    uLong size_to_read;\n\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n    if (pfile_in_zip_read_info==NULL)\n        return UNZ_PARAMERROR;\n\n    size_to_read = (pfile_in_zip_read_info->size_local_extrafield -\n                pfile_in_zip_read_info->pos_local_extrafield);\n\n    if (buf==NULL)\n        return (int)size_to_read;\n\n    if (len>size_to_read)\n        read_now = (uInt)size_to_read;\n    else\n        read_now = (uInt)len ;\n\n    if (read_now==0)\n        return 0;\n\n    if (ZSEEK(pfile_in_zip_read_info->z_filefunc,\n              pfile_in_zip_read_info->filestream,\n              pfile_in_zip_read_info->offset_local_extrafield +\n              pfile_in_zip_read_info->pos_local_extrafield,\n              ZLIB_FILEFUNC_SEEK_SET)!=0)\n        return UNZ_ERRNO;\n\n    if (ZREAD(pfile_in_zip_read_info->z_filefunc,\n              pfile_in_zip_read_info->filestream,\n              buf,read_now)!=read_now)\n        return UNZ_ERRNO;\n\n    return (int)read_now;\n}\n\n/*\n  Close the file in zip opened with unzipOpenCurrentFile\n  Return UNZ_CRCERROR if all the file was read but the CRC is not good\n*/\nextern int ZEXPORT unzCloseCurrentFile (file)\n    unzFile file;\n{\n    int err=UNZ_OK;\n\n    unz_s* s;\n    file_in_zip_read_info_s* pfile_in_zip_read_info;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n    pfile_in_zip_read_info=s->pfile_in_zip_read;\n\n    if (pfile_in_zip_read_info==NULL)\n        return UNZ_PARAMERROR;\n\n\n    if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&\n        (!pfile_in_zip_read_info->raw))\n    {\n        if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)\n            err=UNZ_CRCERROR;\n    }\n\n\n    TRYFREE(pfile_in_zip_read_info->read_buffer);\n    pfile_in_zip_read_info->read_buffer = NULL;\n    if (pfile_in_zip_read_info->stream_initialised)\n        inflateEnd(&pfile_in_zip_read_info->stream);\n\n    pfile_in_zip_read_info->stream_initialised = 0;\n    TRYFREE(pfile_in_zip_read_info);\n\n    s->pfile_in_zip_read=NULL;\n\n    return err;\n}\n\n\n/*\n  Get the global comment string of the ZipFile, in the szComment buffer.\n  uSizeBuf is the size of the szComment buffer.\n  return the number of byte copied or an error code <0\n*/\nextern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf)\n    unzFile file;\n    char *szComment;\n    uLong uSizeBuf;\n{\n    unz_s* s;\n    uLong uReadThis ;\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n\n    uReadThis = uSizeBuf;\n    if (uReadThis>s->gi.size_comment)\n        uReadThis = s->gi.size_comment;\n\n    if (ZSEEK(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0)\n        return UNZ_ERRNO;\n\n    if (uReadThis>0)\n    {\n      *szComment='\\0';\n      if (ZREAD(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis)\n        return UNZ_ERRNO;\n    }\n\n    if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))\n        *(szComment+s->gi.size_comment)='\\0';\n    return (int)uReadThis;\n}\n\n/* Additions by RX '2004 */\nextern uLong ZEXPORT unzGetOffset (file)\n    unzFile file;\n{\n    unz_s* s;\n\n    if (file==NULL)\n          return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n    if (!s->current_file_ok)\n      return 0;\n    if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)\n      if (s->num_file==s->gi.number_entry)\n         return 0;\n    return s->pos_in_central_dir;\n}\n\nextern int ZEXPORT unzSetOffset (file, pos)\n        unzFile file;\n        uLong pos;\n{\n    unz_s* s;\n    int err;\n\n    if (file==NULL)\n        return UNZ_PARAMERROR;\n    s=(unz_s*)file;\n\n    s->pos_in_central_dir = pos;\n    s->num_file = s->gi.number_entry;      /* hack */\n    err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,\n                                              &s->cur_file_info_internal,\n                                              NULL,0,NULL,0,NULL,0);\n    s->current_file_ok = (err == UNZ_OK);\n    return err;\n}\n"
  },
  {
    "path": "networking/unzip.h",
    "content": "/* unzip.h -- IO for uncompress .zip files using zlib\n   Version 1.01e, February 12th, 2005\n\n   Copyright (C) 1998-2005 Gilles Vollant\n\n   This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g\n     WinZip, InfoZip tools and compatible.\n\n   Multi volume ZipFile (span) are not supported.\n   Encryption compatible with pkzip 2.04g only supported\n   Old compressions used by old PKZip 1.x are not supported\n\n\n   I WAIT FEEDBACK at mail info@winimage.com\n   Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution\n\n   Condition of use and distribution are the same than zlib :\n\n  This software is provided 'as-is', without any express or implied\n  warranty.  In no event will the authors be held liable for any damages\n  arising from the use of this software.\n\n  Permission is granted to anyone to use this software for any purpose,\n  including commercial applications, and to alter it and redistribute it\n  freely, subject to the following restrictions:\n\n  1. The origin of this software must not be misrepresented; you must not\n     claim that you wrote the original software. If you use this software\n     in a product, an acknowledgment in the product documentation would be\n     appreciated but is not required.\n  2. Altered source versions must be plainly marked as such, and must not be\n     misrepresented as being the original software.\n  3. This notice may not be removed or altered from any source distribution.\n\n  Modified to integrate with WinHttpRequest.\n\n*/\n\n/* for more info about .ZIP format, see\n      http://www.info-zip.org/pub/infozip/doc/appnote-981119-iz.zip\n      http://www.info-zip.org/pub/infozip/doc/\n   PkWare has also a specification at :\n      ftp://ftp.pkware.com/probdesc.zip\n*/\n\n#ifndef _unz_H\n#define _unz_H\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n#ifndef _ZLIB_H\n#include \"zlib.h\"\n#endif\n\n#ifndef _ZLIBIOAPI_H\n#include \"ioapi.h\"\n#endif\n\n#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)\n\t/* like the STRICT of WIN32, we define a pointer that cannot be converted\n\t    from (void*) without cast */\n\ttypedef struct TagunzFile__ { int unused; } unzFile__;\n\ttypedef unzFile__* unzFile;\n#else\n\ttypedef voidp unzFile;\n#endif\n\n\n#define UNZ_OK                          (0)\n#define UNZ_END_OF_LIST_OF_FILE         (-100)\n#define UNZ_ERRNO                       (Z_ERRNO)\n#define UNZ_EOF                         (0)\n#define UNZ_PARAMERROR                  (-102)\n#define UNZ_BADZIPFILE                  (-103)\n#define UNZ_INTERNALERROR               (-104)\n#define UNZ_CRCERROR                    (-105)\n\n\t/* tm_unz contain date/time info */\n\ttypedef struct tm_unz_s\n\t{\n\t\tuInt tm_sec;            /* seconds after the minute - [0,59] */\n\t\tuInt tm_min;            /* minutes after the hour - [0,59] */\n\t\tuInt tm_hour;           /* hours since midnight - [0,23] */\n\t\tuInt tm_mday;           /* day of the month - [1,31] */\n\t\tuInt tm_mon;            /* months since January - [0,11] */\n\t\tuInt tm_year;           /* years - [1980..2044] */\n\t} tm_unz;\n\n\t/* unz_global_info structure contain global data about the ZIPfile\n\t   These data comes from the end of central dir */\n\ttypedef struct unz_global_info_s\n\t{\n\t\tuLong number_entry;         /* total number of entries in\n                       the central dir on this disk */\n\t\tuLong size_comment;         /* size of the global comment of the zipfile */\n\t} unz_global_info;\n\n\n\t/* unz_file_info contain information about a file in the zipfile */\n\ttypedef struct unz_file_info_s\n\t{\n\t\tuLong version;              /* version made by                 2 bytes */\n\t\tuLong version_needed;       /* version needed to extract       2 bytes */\n\t\tuLong flag;                 /* general purpose bit flag        2 bytes */\n\t\tuLong compression_method;   /* compression method              2 bytes */\n\t\tuLong dosDate;              /* last mod file date in Dos fmt   4 bytes */\n\t\tuLong crc;                  /* crc-32                          4 bytes */\n\t\tuLong compressed_size;      /* compressed size                 4 bytes */\n\t\tuLong uncompressed_size;    /* uncompressed size               4 bytes */\n\t\tuLong size_filename;        /* filename length                 2 bytes */\n\t\tuLong size_file_extra;      /* extra field length              2 bytes */\n\t\tuLong size_file_comment;    /* file comment length             2 bytes */\n\n\t\tuLong disk_num_start;       /* disk number start               2 bytes */\n\t\tuLong internal_fa;          /* internal file attributes        2 bytes */\n\t\tuLong external_fa;          /* external file attributes        4 bytes */\n\n\t\ttm_unz tmu_date;\n\t} unz_file_info;\n\n\textern int ZEXPORT unzStringFileNameCompare OF((const char* fileName1,\n\t\t\tconst char* fileName2,\n\t\t\tint iCaseSensitivity));\n\t/*\n\t   Compare two filename (fileName1,fileName2).\n\t   If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)\n\t   If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi\n\t                                or strcasecmp)\n\t   If iCaseSenisivity = 0, case sensitivity is defaut of your operating system\n\t    (like 1 on Unix, 2 on Windows)\n\t*/\n\n\n\textern unzFile ZEXPORT unzOpen OF((voidpf file));\n\t/*\n\t  Open a Zip file. path contain whatever zopen_file from the IO API\n\t  accepts. For Qt implementation it is a pointer to QIODevice, for\n\t  fopen() implementation it's a file name.\n\t     If the zipfile cannot be opened (file don't exist or in not valid), the\n\t       return value is NULL.\n\t     Else, the return value is a unzFile Handle, usable with other function\n\t       of this unzip package.\n\t*/\n\n\textern unzFile ZEXPORT unzOpen2 OF((voidpf file,\n\t\t\t\t\t\t\t\t\t\tzlib_filefunc_def* pzlib_filefunc_def));\n\t/*\n\t   Open a Zip file, like unzOpen, but provide a set of file low level API\n\t      for read/write the zip file (see ioapi.h)\n\t*/\n\n\textern int ZEXPORT unzClose OF((unzFile file));\n\t/*\n\t  Close a ZipFile opened with unzipOpen.\n\t  If there is files inside the .Zip opened with unzOpenCurrentFile (see later),\n\t    these files MUST be closed with unzipCloseCurrentFile before call unzipClose.\n\t  return UNZ_OK if there is no problem. */\n\n\textern int ZEXPORT unzGetGlobalInfo OF((unzFile file,\n\t\t\t\t\t\t\t\t\t\t\tunz_global_info* pglobal_info));\n\t/*\n\t  Write info about the ZipFile in the *pglobal_info structure.\n\t  No preparation of the structure is needed\n\t  return UNZ_OK if there is no problem. */\n\n\n\textern int ZEXPORT unzGetGlobalComment OF((unzFile file,\n\t\t\tchar* szComment,\n\t\t\tuLong uSizeBuf));\n\t/*\n\t  Get the global comment string of the ZipFile, in the szComment buffer.\n\t  uSizeBuf is the size of the szComment buffer.\n\t  return the number of byte copied or an error code <0\n\t*/\n\n\n\t/***************************************************************************/\n\t/* Unzip package allow you browse the directory of the zipfile */\n\n\textern int ZEXPORT unzGoToFirstFile OF((unzFile file));\n\t/*\n\t  Set the current file of the zipfile to the first file.\n\t  return UNZ_OK if there is no problem\n\t*/\n\n\textern int ZEXPORT unzGoToNextFile OF((unzFile file));\n\t/*\n\t  Set the current file of the zipfile to the next file.\n\t  return UNZ_OK if there is no problem\n\t  return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.\n\t*/\n\n\textern int ZEXPORT unzLocateFile OF((unzFile file,\n\t\t\t\t\t\t\t\t\t\t const char* szFileName,\n\t\t\t\t\t\t\t\t\t\t int iCaseSensitivity));\n\t/*\n\t  Try locate the file szFileName in the zipfile.\n\t  For the iCaseSensitivity signification, see unzStringFileNameCompare\n\n\t  return value :\n\t  UNZ_OK if the file is found. It becomes the current file.\n\t  UNZ_END_OF_LIST_OF_FILE if the file is not found\n\t*/\n\n\n\t/* ****************************************** */\n\t/* Ryan supplied functions */\n\t/* unz_file_info contain information about a file in the zipfile */\n\ttypedef struct unz_file_pos_s\n\t{\n\t\tuLong pos_in_zip_directory;   /* offset in zip file directory */\n\t\tuLong num_of_file;            /* # of file */\n\t} unz_file_pos;\n\n\textern int ZEXPORT unzGetFilePos(\n\t\tunzFile file,\n\t\tunz_file_pos* file_pos);\n\n\textern int ZEXPORT unzGoToFilePos(\n\t\tunzFile file,\n\t\tunz_file_pos* file_pos);\n\n\t/* ****************************************** */\n\n\textern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,\n\t\t\tunz_file_info* pfile_info,\n\t\t\tchar* szFileName,\n\t\t\tuLong fileNameBufferSize,\n\t\t\tvoid* extraField,\n\t\t\tuLong extraFieldBufferSize,\n\t\t\tchar* szComment,\n\t\t\tuLong commentBufferSize));\n\t/*\n\t  Get Info about the current file\n\t  if pfile_info!=NULL, the *pfile_info structure will contain somes info about\n\t        the current file\n\t  if szFileName!=NULL, the filemane string will be copied in szFileName\n\t            (fileNameBufferSize is the size of the buffer)\n\t  if extraField!=NULL, the extra field information will be copied in extraField\n\t            (extraFieldBufferSize is the size of the buffer).\n\t            This is the Central-header version of the extra field\n\t  if szComment!=NULL, the comment string of the file will be copied in szComment\n\t            (commentBufferSize is the size of the buffer)\n\t*/\n\n\t/***************************************************************************/\n\t/* for reading the content of the current zipfile, you can open it, read data\n\t   from it, and close it (you can close it before reading all the file)\n\t   */\n\n\textern int ZEXPORT unzOpenCurrentFile OF((unzFile file));\n\t/*\n\t  Open for reading data the current file in the zipfile.\n\t  If there is no error, the return value is UNZ_OK.\n\t*/\n\n\textern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,\n\t\t\tconst char* password));\n\t/*\n\t  Open for reading data the current file in the zipfile.\n\t  password is a crypting password\n\t  If there is no error, the return value is UNZ_OK.\n\t*/\n\n\textern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,\n\t\t\tint* method,\n\t\t\tint* level,\n\t\t\tint raw));\n\t/*\n\t  Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)\n\t    if raw==1\n\t  *method will receive method of compression, *level will receive level of\n\t     compression\n\t  note : you can set level parameter as NULL (if you did not want known level,\n\t         but you CANNOT set method parameter as NULL\n\t*/\n\n\textern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,\n\t\t\tint* method,\n\t\t\tint* level,\n\t\t\tint raw,\n\t\t\tconst char* password));\n\t/*\n\t  Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)\n\t    if raw==1\n\t  *method will receive method of compression, *level will receive level of\n\t     compression\n\t  note : you can set level parameter as NULL (if you did not want known level,\n\t         but you CANNOT set method parameter as NULL\n\t*/\n\n\n\textern int ZEXPORT unzCloseCurrentFile OF((unzFile file));\n\t/*\n\t  Close the file in zip opened with unzOpenCurrentFile\n\t  Return UNZ_CRCERROR if all the file was read but the CRC is not good\n\t*/\n\n\textern int ZEXPORT unzReadCurrentFile OF((unzFile file,\n\t\t\tvoidp buf,\n\t\t\tunsigned len));\n\t/*\n\t  Read bytes from the current file (opened by unzOpenCurrentFile)\n\t  buf contain buffer where data must be copied\n\t  len the size of buf.\n\n\t  return the number of byte copied if somes bytes are copied\n\t  return 0 if the end of file was reached\n\t  return <0 with error code if there is an error\n\t    (UNZ_ERRNO for IO error, or zLib error for uncompress error)\n\t*/\n\n\textern z_off_t ZEXPORT unztell OF((unzFile file));\n\t/*\n\t  Give the current position in uncompressed data\n\t*/\n\n\textern int ZEXPORT unzeof OF((unzFile file));\n\t/*\n\t  return 1 if the end of file was reached, 0 elsewhere\n\t*/\n\n\textern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,\n\t\t\tvoidp buf,\n\t\t\tunsigned len));\n\t/*\n\t  Read extra field from the current file (opened by unzOpenCurrentFile)\n\t  This is the local-header version of the extra field (sometimes, there is\n\t    more info in the local-header version than in the central-header)\n\n\t  if buf==NULL, it return the size of the local extra field\n\n\t  if buf!=NULL, len is the size of the buffer, the extra header is copied in\n\t    buf.\n\t  the return value is the number of bytes copied in buf, or (if <0)\n\t    the error code\n\t*/\n\n\t/***************************************************************************/\n\n\t/* Get the current file offset */\n\textern uLong ZEXPORT unzGetOffset(unzFile file);\n\n\t/* Set the current file offset */\n\textern int ZEXPORT unzSetOffset(unzFile file, uLong pos);\n\n\n\n#ifdef __cplusplus\n}\n#endif\n\n#endif /* _unz_H */\n"
  },
  {
    "path": "remove_pytube.cmd",
    "content": "RD \"%LOCALAPPDATA%\\pytube-master\" /S /Q\n"
  },
  {
    "path": "remove_youtube_transcript_api.cmd",
    "content": "RD \"%LOCALAPPDATA%\\youtube-transcript-api-master\" /S /Q\n"
  },
  {
    "path": "video/audioparserunnable.cpp",
    "content": "#include \"ffmpegdecoder.h\"\n#include \"makeguard.h\"\n#include \"interlockedadd.h\"\n\n#include <boost/log/trivial.hpp>\n\n#include <algorithm>\n#include <functional>\n#include <memory>\n#include <tuple>\n\n\nnamespace {\n\nuint8_t** getAudioData(AVFrame* audioFrame)\n{\n    return audioFrame->extended_data != nullptr\n        ? audioFrame->extended_data\n        : &audioFrame->data[0];\n}\n\n#if LIBAVUTIL_VERSION_MAJOR < 57\n\nint64_t getChannelLayout(AVFrame* audioFrame)\n{\n\tconst int audioFrameChannels = audioFrame->channels;\n    return ((audioFrame->channel_layout != 0u) &&\n        audioFrameChannels == av_get_channel_layout_nb_channels(audioFrame->channel_layout))\n        ? audioFrame->channel_layout\n        : av_get_default_channel_layout(audioFrameChannels);\n}\n\n#else\n\nauto getChannelLayout(AVFrame* audioFrame)\n{\n    return audioFrame->ch_layout;\n}\n\nbool operator == (const AVChannelLayout& left, const AVChannelLayout& right)\n{\n    return av_channel_layout_compare(&left, &right) == 0;\n}\n\nbool operator != (const AVChannelLayout& left, const AVChannelLayout& right)\n{\n    return av_channel_layout_compare(&left, &right) != 0;\n}\n\n#endif\n\n} // namespace\n\n\nFFmpegDecoder::AudioParams::AudioParams(int freq, int chans, AVSampleFormat fmt) \n    : frequency(freq), format(fmt)\n{\n#if LIBAVUTIL_VERSION_MAJOR < 57\n    channels = chans;\n    channel_layout = av_get_default_channel_layout(chans);\n#else\n    av_channel_layout_default(&channel_layout, chans);\n#endif\n}\n\nFFmpegDecoder::AudioParams::~AudioParams()\n{\n#if LIBAVUTIL_VERSION_MAJOR >= 57\n    av_channel_layout_uninit(&channel_layout);\n#endif\n}\n\nFFmpegDecoder::AudioParams& \nFFmpegDecoder::AudioParams::operator =(const FFmpegDecoder::AudioParams& other)\n{\n    frequency = other.frequency;\n    format = other.format;\n#if LIBAVUTIL_VERSION_MAJOR < 57\n    channels = other.channels;\n    channel_layout = other.channel_layout;\n#else\n    av_channel_layout_uninit(&channel_layout);\n    av_channel_layout_copy(&channel_layout, &other.channel_layout);\n#endif\n    return *this;\n}\n\n\nvoid FFmpegDecoder::audioParseRunnable()\n{\n    CHANNEL_LOG(ffmpeg_threads) << \"Audio thread started\";\n    bool initialized = false;\n    bool failed = false;\n\n    m_audioPlayer->InitializeThread();\n    auto deinitializeThread = MakeGuard(\n        m_audioPlayer.get(),\n        std::mem_fn(&IAudioPlayer::DeinitializeThread));\n\n    std::vector<uint8_t> resampleBuffer;\n\n    double scheduledEndTime = 0;\n\n    auto useHandleAudioResultLam = [this, &failed](bool result)\n    {\n        if (result)\n        {\n            if (failed)\n            {\n                failed = false;\n                boost::lock_guard<boost::mutex> locker(m_isPausedMutex);\n                if (m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED)\n                {\n                    m_audioPTS = (m_isPaused ? m_pauseTimer : GetHiResTime()) - m_videoStartClock;\n                }\n            }\n        }\n        else\n        {\n            failed = true;\n        }\n    };\n\n    while (!boost::this_thread::interruption_requested())\n    {\n        AVPacket packet;\n        if (!m_audioPacketsQueue.pop(packet))\n        {\n            break;\n        }\n\n        auto packetGuard = MakeGuard(&packet, av_packet_unref);\n\n        if (m_audioStreamNumber != packet.stream_index)\n        {\n            continue;\n        }\n\n        if (!initialized)\n        {\n            if (packet.pts == AV_NOPTS_VALUE)\n            {\n                if (packet.data == nullptr)\n                    continue;\n\n                assert(false && \"No audio pts found\");\n                return;\n            }\n            const double pts = av_q2d(m_audioStream->time_base) * packet.pts;\n            m_audioPTS = pts;\n            scheduledEndTime = pts;\n            // invoke changedFramePosition() if needed\n            //AppendFrameClock(0);\n        }\n        else if (packet.pts != AV_NOPTS_VALUE)\n        {\n            const double diff = av_q2d(m_audioStream->time_base) * packet.pts - scheduledEndTime;\n            if (diff > 0.01)\n            {\n                CHANNEL_LOG(ffmpeg_sync) << \"Patching audio frame diff: \" << diff;\n                if (m_formatContexts.size() == 1 && m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED)\n                {\n                    InterLockedAdd(m_videoStartClock, -diff);\n                    InterLockedAdd(m_audioPTS, diff);\n                }\n                else\n                {\n                    const int size_multiplier = m_audioSettings.num_channels() *\n                        av_get_bytes_per_sample(m_audioSettings.format);\n\n                    const int numSteps = (diff + 0.1) / 0.1;\n                    const auto frame_clock = diff / numSteps;\n                    for (int i = 0; i < numSteps; ++i)\n                    {\n                        const auto speed = getSpeedRational();\n                        const int nb_samples = frame_clock * m_audioSettings.frequency * speed.denominator / speed.numerator;\n                        const auto write_size = nb_samples * size_multiplier;\n                        std::vector<uint8_t> buf(write_size, 0);\n                        useHandleAudioResultLam(handleAudioFrame(frame_clock, buf.data(), write_size, failed));\n                    }\n                }\n            }\n\n            scheduledEndTime += diff;\n        }\n\n        initialized = true;\n\n        useHandleAudioResultLam(handleAudioPacket(packet, resampleBuffer, failed, scheduledEndTime));\n    }\n}\n\nbool FFmpegDecoder::handleAudioPacket(\n    const AVPacket& packet,\n    std::vector<uint8_t>& resampleBuffer,\n    bool failed, double& scheduledEndTime)\n{\n    if (packet.stream_index != m_audioStream->index)\n    {\n        avcodec_free_context(&m_audioCodecContext);\n        m_audioStream = m_formatContexts[m_audioContextIndex]->streams[packet.stream_index];\n        m_audioCodecContext = avcodec_alloc_context3(nullptr);\n        if (m_audioCodecContext == nullptr) {\n            return false;\n        }\n        if (!setupAudioCodec())\n        {\n            return false;\n        }\n    }\n\n    if (m_audioCodecContext == nullptr) {\n        return false;\n    }\n    const int ret = avcodec_send_packet(m_audioCodecContext, &packet);\n    if (ret < 0) {\n        return ret == AVERROR(EAGAIN) || ret == AVERROR_EOF;\n    }\n\n    AVFramePtr audioFrame(av_frame_alloc());\n    bool result = true;\n    while (avcodec_receive_frame(m_audioCodecContext, audioFrame.get()) == 0)\n    {\n        if (audioFrame->nb_samples <= 0)\n        {\n            continue;\n        }\n\n        const int original_buffer_size = av_samples_get_buffer_size(\n            nullptr,\n#if LIBAVUTIL_VERSION_MAJOR < 57\n            audioFrame->channels,\n#else\n            audioFrame->ch_layout.nb_channels,\n#endif\n            audioFrame->nb_samples,\n            static_cast<AVSampleFormat>(audioFrame->format), 1);\n\n        // write buffer\n        uint8_t* write_data = *getAudioData(audioFrame.get());\n        int64_t write_size = original_buffer_size;\n\n        setupAudioSwrContext(audioFrame.get());\n\n        if (m_audioSwrContext != nullptr)\n        {\n            enum { EXTRA_SPACE = 256 };\n\n            const int out_count = static_cast<int64_t>(audioFrame->nb_samples) *\n                m_audioSettings.frequency /\n                m_audioCurrentPref.frequency + EXTRA_SPACE;\n\n            const int size_multiplier = m_audioSettings.num_channels() *\n                av_get_bytes_per_sample(m_audioSettings.format);\n\n            const size_t buffer_size = out_count * size_multiplier;\n\n            if (resampleBuffer.size() < buffer_size)\n            {\n                resampleBuffer.resize(buffer_size);\n            }\n\n            // Code for resampling\n            uint8_t *out = resampleBuffer.data();\n            const int converted_size = swr_convert(\n                m_audioSwrContext, \n                &out,\n                out_count,\n                const_cast<const uint8_t**>(getAudioData(audioFrame.get())),\n                audioFrame->nb_samples);\n\n            if (converted_size < 0)\n            {\n                BOOST_LOG_TRIVIAL(error) << \"swr_convert() failed\";\n                break;\n            }\n\n            if (converted_size == out_count)\n            {\n                BOOST_LOG_TRIVIAL(warning) << \"audio buffer is probably too small\";\n                swr_init(m_audioSwrContext);\n            }\n\n            write_data = out;\n            write_size = converted_size * size_multiplier;\n\n            assert(write_size < buffer_size);\n        }\n\n        const double frame_clock \n            = audioFrame->sample_rate != 0? double(audioFrame->nb_samples) / audioFrame->sample_rate : 0;\n\n        scheduledEndTime += frame_clock;\n\n        if (!handleAudioFrame(frame_clock, write_data, write_size, failed))\n        {\n            result = false;\n        }\n    }\n\n    return result;\n}\n\nvoid FFmpegDecoder::setupAudioSwrContext(AVFrame* audioFrame)\n{\n    const auto audioFrameFormat = static_cast<AVSampleFormat>(audioFrame->format);\n\n    auto dec_channel_layout = getChannelLayout(audioFrame);\n\n    const auto speed = getSpeedRational();\n\n    // Check if the new swr context required\n    if (m_audioSwrContext == nullptr || audioFrameFormat != m_audioCurrentPref.format ||\n        dec_channel_layout != m_audioCurrentPref.channel_layout ||\n        (audioFrame->sample_rate * speed.numerator) / speed.denominator != m_audioCurrentPref.frequency)\n    {\n\n        swr_free(&m_audioSwrContext);\n\n#if LIBAVUTIL_VERSION_MAJOR < 57\n\n        m_audioSwrContext = swr_alloc_set_opts(\n            nullptr, m_audioSettings.channel_layout, m_audioSettings.format,\n            m_audioSettings.frequency * speed.denominator,\n            dec_channel_layout, audioFrameFormat,\n            audioFrame->sample_rate * speed.numerator, 0, nullptr);\n\n#else\n\n        swr_alloc_set_opts2(&m_audioSwrContext, &m_audioSettings.channel_layout,\n            m_audioSettings.format,\n            m_audioSettings.frequency * speed.denominator,\n            &dec_channel_layout, audioFrameFormat,\n            audioFrame->sample_rate * speed.numerator, 0, nullptr);\n\n#endif\n\n\n        if ((m_audioSwrContext == nullptr) || swr_init(m_audioSwrContext) < 0)\n        {\n            BOOST_LOG_TRIVIAL(error) << \"unable to initialize swr convert context\";\n        }\n\n        m_audioCurrentPref.format = audioFrameFormat;\n#if LIBAVUTIL_VERSION_MAJOR < 57\n        m_audioCurrentPref.channels = audioFrame->channels;\n        m_audioCurrentPref.channel_layout = dec_channel_layout;\n#else\n        av_channel_layout_uninit(&m_audioCurrentPref.channel_layout);\n        av_channel_layout_copy(&m_audioCurrentPref.channel_layout, &dec_channel_layout);\n#endif\n        m_audioCurrentPref.frequency = (audioFrame->sample_rate * speed.numerator) / speed.denominator;\n    }\n}\n\nbool FFmpegDecoder::handleAudioFrame(\n    double frame_clock, uint8_t* write_data, int64_t write_size, bool failed)\n{\n    bool skipAll = false;\n    double delta = 0;\n    bool isPaused = false;\n\n    {\n        boost::lock_guard<boost::mutex> locker(m_isPausedMutex);\n        isPaused = m_isPaused;\n        if (!isPaused)\n        {\n            delta = (m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED)\n                ? GetHiResTime() - m_videoStartClock - m_audioPTS : 0;\n        }\n    }\n\n    if (isPaused)\n    {\n        if (!m_audioPaused)\n        {\n            m_audioPlayer->WaveOutPause();\n            m_audioPaused = true;\n        }\n\n        boost::unique_lock<boost::mutex> locker(m_isPausedMutex);\n\n        while (delta = (m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED)\n                ? (m_isPaused ? m_pauseTimer : GetHiResTime()) - m_videoStartClock - m_audioPTS : 0\n                , m_isPaused && !(skipAll = delta >= frame_clock))\n        {\n            m_isPausedCV.wait(locker);\n        }\n    }\n    else if (delta > 1 && m_formatContexts.size() > 1 && delta > frame_clock)\n    {\n        CHANNEL_LOG(ffmpeg_sync) << \"Skip audio frame\";\n        skipAll = true;\n    }\n\n    if (!skipAll && m_mainVideoThread != nullptr\n        && std::all_of(write_data, write_data + write_size, [](uint8_t data) { return data == 0; })\n        //&& m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED\n        && m_videoPacketsQueue.empty()\n        && (boost::lock_guard<boost::mutex>(m_videoFramesMutex), !m_videoFramesQueue.canPop()))\n    {\n        return true; // just ignore?\n    }\n\n    // Audio sync\n    if (!failed && !skipAll && fabs(delta) > 0.1)\n    {\n        CHANNEL_LOG(ffmpeg_sync) << \"Audio sync delta = \" << delta;\n        InterLockedAdd(m_videoStartClock, delta / 2);\n    }\n\n    if (m_audioPaused && !skipAll)\n    {\n        m_audioPlayer->WaveOutRestart();\n        m_audioPaused = false;\n    }\n\n    boost::this_thread::interruption_point();\n\n    if (skipAll)\n    {\n        InterLockedAdd(m_audioPTS, frame_clock);\n        return true;\n    }\n\n    return m_audioPlayer->WriteAudio(write_data, write_size)\n        || (m_audioPlayer->Close(), initAudioOutput())\n        && (swr_free(&m_audioSwrContext), m_audioPlayer->WriteAudio(write_data, write_size));\n}\n"
  },
  {
    "path": "video/audioplayer.h",
    "content": "#pragma once\n\n#include <cstdint>\n\nstruct IAudioPlayerCallback\n{\n    virtual void AppendFrameClock(double frame_clock) = 0;\n};\n\nstruct IAudioPlayer\n{\n    virtual ~IAudioPlayer() = default;\n    virtual void SetCallback(IAudioPlayerCallback* callback) = 0;\n\n    virtual void InitializeThread() = 0;\n    virtual void DeinitializeThread() = 0;\n\n    virtual void Close() = 0;\n    virtual bool Open(int bytesPerSample, int channels, int* samplesPerSec) = 0;\n\n    virtual void SetVolume(double volume) = 0;\n    virtual double GetVolume() const = 0;\n\n    // stops playback on the given output device and resets the current position\n    virtual void WaveOutReset() = 0;\n    // pauses playback on the given output device\n    virtual void WaveOutPause() = 0;\n    // resumes playback on a paused output device\n    virtual void WaveOutRestart() = 0;\n\n    virtual bool WriteAudio(uint8_t* write_data, int64_t write_size) = 0;\n};\n"
  },
  {
    "path": "video/decoderinterface.h",
    "content": "#pragma once\n\n#include \"ordered_scoped_token.h\"\n\n#include <cstdint>\n#include <memory>\n#include <string>\n#include <utility>\n#include <vector>\n#include <initializer_list>\n#include <functional>\n#include <streambuf>\n\n\nstruct IDirect3DDevice9;\nstruct IDirect3DSurface9;\n\nstruct IFrameDecoder;\n\n// Structure holding rendering data for a frame\nstruct FrameRenderingData\n{\n    uint8_t** image{};      // Pointer to frame image data\n    const int* pitch{};     // Pointer to pitch (stride) values for each plane\n    int width;              // Frame width\n    int height;             // Frame height\n    int aspectNum;          // Numerator of aspect ratio\n    int aspectDen;          // Denominator of aspect ratio\n\n    IDirect3DDevice9* d3d9device{};   // Direct3D device interface\n    IDirect3DSurface9* surface{};     // Direct3D surface for rendering\n};\n\n// Interface for listening to frame updates\nstruct IFrameListener\n{\n    virtual ~IFrameListener() = default;\n    virtual void updateFrame(IFrameDecoder* decoder, unsigned int generation) = 0; // Called to update frame data\n    virtual void drawFrame(IFrameDecoder* decoder, unsigned int generation) = 0;  // Called to draw frame; decoder->finishedDisplayingFrame() must be called\n    virtual void decoderClosing() = 0; // Called when decoder is closing\n};\n\n// Interface for decoder event notifications\nstruct FrameDecoderListener\n{\n    virtual ~FrameDecoderListener() = default;\n\n    virtual void changedFramePosition(long long /*start*/, long long /*frame*/, long long /*total*/) {}\n    virtual void decoderClosed(bool /*fileReleased*/) {}   // Notification of decoder closure\n    virtual void fileLoaded(long long /*start*/, long long /*total*/) {} // Called when a file has been successfully loaded\n    virtual void volumeChanged(double /*volume*/) {}  // Called when volume level changes\n\n    virtual void onEndOfStream(int /*idx*/, bool /*error*/) {} // Called when the end of the stream is reached\n    virtual void onQueueFull(int /*idx*/) {}  // Called when the frame queue is full\n\n    virtual void playingFinished() {}  // Called when playback finishes\n};\n\n// Structure representing a rational number\nstruct RationalNumber\n{\n    int numerator;   // Numerator of fraction\n    int denominator; // Denominator of fraction\n};\n\n// Equality operator for RationalNumber\ninline bool operator==(const RationalNumber& left, const RationalNumber& right)\n{\n    return left.numerator == right.numerator && left.denominator == right.denominator;\n}\n\n// Interface for video frame decoding\nstruct IFrameDecoder\n{\n    // Supported pixel formats for frames\n    enum FrameFormat {\n        PIX_FMT_YUV420P,   ///< Planar YUV 4:2:0 format, 12 bits per pixel\n        PIX_FMT_YUYV422,   ///< Packed YUV 4:2:2 format, 16 bits per pixel\n        PIX_FMT_RGB24,     ///< Packed RGB format (8 bits per channel)\n        PIX_FMT_BGR24,     ///< Packed BGR format (8 bits per channel)\n    };\n\n    // Possible modes after displaying a frame. Controls how the decoder handles\n    // frame memory and display state once a frame is no longer needed.\n    enum FinishedDisplayingMode {\n        RELEASE_FRAME,       ///< Release memory associated with the frame only.\n        ///< Use when frame data is not required anymore,\n        ///< but no explicit \"end of display\" notification\n        ///< is desired.\n\n        FINALIZE_DISPLAY,    ///< Mark display of this frame as complete without\n        ///< releasing its memory. Typically used if another\n        ///< subsystem (e.g. GPU renderer) still needs access\n        ///< to the frame buffers until it decides to release.\n\n        RELEASE_AND_FINALIZE ///< (Default) Both release frame memory and finalize\n                             ///< display. This is the safest option in most cases\n                             ///< and should be used unless special handling is\n                             ///< required.\n    };\n\n    // Function type for performing image conversion; NV12 format\n    typedef std::function<bool(OrderedScopedTokenGenerator::Token,\n        uint8_t* /*input*/, int /*input stride*/, int /*input width*/, int /*input height*/,\n        int64_t /*pts*/, std::vector<uint8_t>& /*output*/, int& /*output width*/, int& /*output height*/\n        )> ImageConversionFunc;\n\n    virtual ~IFrameDecoder() = default;\n\n    // Set frame format and whether Direct3D data should be allowed\n    virtual void SetFrameFormat(FrameFormat format, bool allowDirect3dData) = 0;\n\n    // Open video streams or URLs\n    virtual bool openUrls(std::initializer_list<std::string> urls, const std::string& inputFormat = {}, bool useHHO = false) = 0;\n    virtual bool openStream(std::unique_ptr<std::streambuf> stream) = 0;\n\n    // Playback controls\n    virtual void play(bool isPaused = false) = 0;\n    virtual bool pauseResume() = 0;\n    virtual bool nextFrame() = 0;\n    virtual bool prevFrame() = 0;\n    virtual void setVolume(double volume) = 0;\n\n    virtual bool seekByPercent(double percent) = 0;\n    virtual void videoReset() = 0;\n\n    // Set event listeners\n    virtual void setFrameListener(IFrameListener* listener) = 0;\n    virtual void setDecoderListener(FrameDecoderListener* listener) = 0;\n\n    // Retrieve rendering data\n    virtual bool getFrameRenderingData(FrameRenderingData* data) = 0;\n\n    virtual void doOnFinishedDisplayingFrame(unsigned int generation, FinishedDisplayingMode mode) = 0;\n\n    // Notifies the decoder that a frame has finished displaying.\n    //\n    // Must be called exactly once for each frame that was passed to\n    // IFrameListener::drawFrame(). This function may be called from\n    // any thread, including UI/rendering threads, but the caller must\n    // ensure correct synchronization.\n    //\n    // Parameters:\n    //   generation - Frame generation number received with drawFrame()\n    //   mode       - Frame release mode (defaults to RELEASE_AND_FINALIZE)\n    //\n    // Calling this function incorrectly (e.g., missing calls or wrong\n    // mode) may result in memory leaks, excessive buffering, or playback stalls.\n    void finishedDisplayingFrame(unsigned int generation, FinishedDisplayingMode mode = RELEASE_AND_FINALIZE)\n    {\n        doOnFinishedDisplayingFrame(generation, mode);\n    }\n\n    virtual void close() = 0;\n\n    // Playback status queries\n    virtual bool isPlaying() const = 0;\n    virtual bool isPaused() const = 0;\n    virtual double volume() const = 0;\n    virtual double getDurationSecs(int64_t duration) const = 0;\n\n    // Audio track management\n    virtual int getNumAudioTracks() const = 0;\n    virtual int getAudioTrack() const = 0;\n    virtual void setAudioTrack(int idx) = 0;\n\n    // Speed control\n    virtual RationalNumber getSpeedRational() const = 0;\n    virtual void setSpeedRational(const RationalNumber& speed) = 0;\n\n    // Hardware acceleration control\n    virtual bool getHwAccelerated() const = 0;\n    virtual void setHwAccelerated(bool hwAccelerated) = 0;\n\n    // Retrieve properties of the content\n    virtual std::vector<std::string> getProperties() const = 0;\n\n    // Retrieve video size\n    virtual std::pair<int, int> getVideoSize() const = 0;\n\n    // Check compatibility of video and audio streams\n    virtual std::pair<bool, bool> isVideoAudioCompatible() const = 0;\n\n    // Subtitle handling\n    virtual std::vector<std::string> listSubtitles() const = 0;\n    virtual bool getSubtitles(int idx, std::function<bool(double, double, const std::string&)> addIntervalCallback) = 0;\n\n    // Set custom image conversion function\n    virtual void setImageConversionFunc(ImageConversionFunc func) = 0;\n};\n\nstruct IAudioPlayer;\n\n// Function to retrieve a frame decoder with an associated audio player\nstd::unique_ptr<IFrameDecoder> GetFrameDecoder(std::unique_ptr<IAudioPlayer> audioPlayer);\n"
  },
  {
    "path": "video/decoderiocontext.cpp",
    "content": "#include \"decoderiocontext.h\"\n\nextern \"C\"\n{\n#include <libavformat/avformat.h>\n}\n\n\n// static\nint DecoderIOContext::IOReadFunc(void *data, uint8_t *buf, int buf_size)\n{\n    auto *hctx = static_cast<DecoderIOContext*>(data);\n    try\n    {\n        auto len = hctx->stream->sgetn((char*)buf, buf_size);\n        if (len <= 0)\n        {\n            // Let FFmpeg know that we have reached EOF, or do something else\n            return AVERROR_EOF;\n        }\n        return static_cast<int>(len);\n    }\n    catch (const std::exception&)\n    {\n        // Handle any exceptions that may occur during sgetn\n        return AVERROR(EIO);\n    }\n}\n\n// whence: SEEK_SET, SEEK_CUR, SEEK_END (like fseek) and AVSEEK_SIZE\n// static\nint64_t DecoderIOContext::IOSeekFunc(void *data, int64_t pos, int whence)\n{\n    auto *hctx = static_cast<DecoderIOContext*>(data);\n\n    if (whence == AVSEEK_SIZE)\n    {\n        // return the file size if you wish to\n        auto current = hctx->stream->pubseekoff(0, std::ios_base::cur, std::ios_base::in);\n        auto result = hctx->stream->pubseekoff(0, std::ios_base::end, std::ios_base::in);\n        hctx->stream->pubseekoff(current, std::ios_base::beg, std::ios_base::in);\n        return result;\n    }\n\n    std::ios_base::seekdir dir;\n    switch (whence)\n    {\n    case SEEK_SET:\n        dir = std::ios_base::beg;\n        break;\n    case SEEK_CUR:\n        dir = std::ios_base::cur;\n        break;\n    case SEEK_END:\n        dir = std::ios_base::end;\n        break;\n    default:\n        return -1LL;\n    }\n\n    return hctx->stream->pubseekoff(pos, dir);\n}\n\nDecoderIOContext::DecoderIOContext(std::unique_ptr<std::streambuf> s)\n    : stream(std::move(s))\n{\n    // allocate buffer\n    bufferSize = 1024 * 64;                                  // FIXME: not sure what size to use\n    buffer = static_cast<uint8_t*>(av_malloc(bufferSize));  // see destructor for details\n\n    // allocate the AVIOContext\n    ioCtx =\n        avio_alloc_context(buffer, bufferSize,  // internal buffer and its size\n                           0,                   // write flag (1=true,0=false)\n                           (void *)this,  // user data, will be passed to our callback functions\n                           IOReadFunc,\n                           nullptr,  // no writing\n                           IOSeekFunc);\n}\n\nDecoderIOContext::~DecoderIOContext()\n{\n    //CHANNEL_LOG(ffmpeg_closing) << \"In DecoderIOContext::~DecoderIOContext()\";\n\n    // NOTE: ffmpeg messes up the buffer\n    // so free the buffer first then free the context\n    av_free(ioCtx->buffer);\n    ioCtx->buffer = nullptr;\n    av_free(ioCtx);\n}\n\nvoid DecoderIOContext::initAVFormatContext(AVFormatContext *pCtx)\n{\n    pCtx->pb = ioCtx;\n    pCtx->flags |= AVFMT_FLAG_CUSTOM_IO;\n\n    // you can specify a format directly\n    // pCtx->iformat = av_find_input_format(\"h264\");\n\n    // or read some of the file and let ffmpeg do the guessing\n    auto len = stream->sgetn((char *)buffer, bufferSize);\n    if (len <= 0)\n    {\n        return;\n    }\n    // reset to beginning of file\n    stream->pubseekoff(0, std::ios_base::beg, std::ios_base::in);\n\n    AVProbeData probeData = {nullptr};\n    probeData.buf = buffer;\n    probeData.buf_size = bufferSize - 1;\n    probeData.filename = \"\";\n    pCtx->iformat = av_probe_input_format(&probeData, 1);\n}\n"
  },
  {
    "path": "video/decoderiocontext.h",
    "content": "#pragma once\n\n#include <cstdint>\n#include <memory>\n#include <streambuf>\n\nstruct AVIOContext;\nstruct AVFormatContext;\n\nclass DecoderIOContext\n{\nprivate:\n    AVIOContext *ioCtx;\n    uint8_t *buffer;  // internal buffer for ffmpeg\n    int bufferSize;\n    std::unique_ptr<std::streambuf> stream;\n\npublic:\n    DecoderIOContext(std::unique_ptr<std::streambuf> s);\n    ~DecoderIOContext();\n\n    void initAVFormatContext(AVFormatContext * /*pCtx*/);\n\n    static int IOReadFunc(void *data, uint8_t *buf, int buf_size);\n    static int64_t IOSeekFunc(void *data, int64_t pos, int whence);\n};\n"
  },
  {
    "path": "video/displayrunnable.cpp",
    "content": "#include \"ffmpegdecoder.h\"\n\n#include <tuple>\n\nvoid FFmpegDecoder::displayRunnable()\n{\n    CHANNEL_LOG(ffmpeg_threads) << \"Displaying thread started\";\n\n#ifdef TRACE_DELAY_STATS\n    double sumIndications = 0;\n    double sqSumIndications = 0;\n\n    enum { MAX_INDICATIONS = 200 };\n    int numIndications = 0;\n#endif\n\n    while (!boost::this_thread::interruption_requested())\n    {\n        {\n            boost::unique_lock<boost::mutex> locker(m_videoFramesMutex);\n            m_videoFramesCV.wait(locker, [this]()\n            {\n                return !m_frameDisplayingRequested &&\n                    m_videoFramesQueue.canPop();\n            });\n        }\n\n        VideoFrame& current_frame = m_videoFramesQueue.front();\n        m_frameDisplayingRequested = true;\n\n        if (current_frame.m_convert.valid() && !current_frame.m_convert.get()) {\n                finishedDisplayingFrame(m_generation);\n                continue;\n        }\n\n        assert(m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED);\n\n        // Frame skip\n        if (!m_videoFramesQueue.canPush()\n            && m_videoStartClock + current_frame.m_pts < GetHiResTime())\n        {\n            CHANNEL_LOG(ffmpeg_threads) << __FUNCTION__ << \" Framedrop\";\n            finishedDisplayingFrame(m_generation);\n            continue;\n        }\n\n        const auto pts = current_frame.m_pts;\n        const auto duration = current_frame.m_duration;\n\n        // Possibly give it time to render frame\n        if (m_frameListener != nullptr)\n        {\n            m_frameListener->updateFrame(this, m_generation);\n        }\n\n        const auto speed = getSpeedRational();\n\n        for (;;)\n        {\n            const double delay = m_videoStartClock + pts - GetHiResTime();\n            if (delay < 0.005) {\n                break;\n            }\n            if (delay > 0.1)\n            {\n                boost::this_thread::sleep_for(\n                    boost::chrono::milliseconds(100 * speed.denominator / speed.numerator));\n                continue;\n            }\n\n            boost::this_thread::sleep_for(\n                boost::chrono::milliseconds(int(delay * 1000. * speed.denominator / speed.numerator)));\n            break;\n        }\n\n        // It's time to display converted frame\n        if (duration != AV_NOPTS_VALUE)\n        {\n            m_currentTime = duration;\n            if ((m_decoderListener != nullptr) && m_seekDuration == AV_NOPTS_VALUE)\n            {\n                m_decoderListener->changedFramePosition(\n                    m_startTime,\n                    duration,\n                    m_duration + m_startTime);\n            }\n        }\n\n#ifdef TRACE_DELAY_STATS\n        const double delay = m_videoStartClock + pts - GetHiResTime();\n        sumIndications += delay;\n        sqSumIndications += delay * delay;\n        if (++numIndications >= MAX_INDICATIONS)\n        {\n            const double avg = sumIndications / numIndications;\n            CHANNEL_LOG(ffmpeg_threads) << \"Average frame delay: \" << avg\n                << \"; frame delay deviation: \" << sqrt(sqSumIndications / numIndications - avg * avg);\n            sumIndications = 0;\n            sqSumIndications = 0;\n            numIndications = 0;\n        }\n#endif\n\n        if (m_frameListener != nullptr)\n        {\n            m_frameListener->drawFrame(this, m_generation);\n        }\n        else\n        {\n            finishedDisplayingFrame(m_generation);\n        }\n    }\n}\n"
  },
  {
    "path": "video/ffmpeg_dxva2.cpp",
    "content": "/*\n* This file is part of FFmpeg.\n*\n* FFmpeg is free software; you can redistribute it and/or\n* modify it under the terms of the GNU Lesser General Public\n* License as published by the Free Software Foundation; either\n* version 2.1 of the License, or (at your option) any later version.\n*\n* FFmpeg is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n* Lesser General Public License for more details.\n*\n* You should have received a copy of the GNU Lesser General Public\n* License along with FFmpeg; if not, write to the Free Software\n* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n*/\n\n#ifdef _WIN32\n\n#include <d3d9.h>\n#include <dxva2api.h>\n\n#include \"ffmpeg_dxva2.h\"\n\nextern \"C\"\n{\n#include \"libavcodec/avcodec.h\"\n#include \"libavutil/pixfmt.h\"\n#include \"libavutil/rational.h\"\n\n#include \"libavcodec/dxva2.h\"\n\n#include \"libavutil/avassert.h\"\n#include \"libavutil/buffer.h\"\n#include \"libavutil/frame.h\"\n#include \"libavutil/imgutils.h\"\n\n#include \"libavutil/cpu.h\"\n}\n\n#include <emmintrin.h>\n#include <smmintrin.h>\n\n#include <algorithm>\n\n\n// https://github.com/NVIDIA/gdrcopy/blob/master/memcpy_sse41.c\n\n// implementation of copy from BAR using MOVNTDQA \n// suggested by Nicholas Wilt <nwilt@amazon.com>\n\n// src is WC MMIO of GPU BAR\n// dest is host memory\nstatic int memcpy_uncached_load_sse41(void *dest, const void *src, size_t n_bytes)\n{\n    int ret = 0;\n\n    char *d = (char*)dest;\n    uintptr_t d_int = (uintptr_t)d;\n    const char *s = (const char *)src;\n    uintptr_t s_int = (uintptr_t)s;\n    size_t n = n_bytes;\n\n    // align src to 128-bits\n    if (s_int & 0xf) {\n        size_t nh = (std::min)(0x10 - (s_int & 0x0f), n);\n        memcpy(d, s, nh);\n        d += nh; d_int += nh;\n        s += nh; s_int += nh;\n        n -= nh;\n    }\n\n    if (d_int & 0xf) { // dest is not aligned to 128-bits\n        __m128i r0, r1, r2, r3, r4, r5, r6, r7;\n        // unroll 8\n        while (n >= 8 * sizeof(__m128i)) {\n            r0 = _mm_stream_load_si128((__m128i *)(s + 0 * sizeof(__m128i)));\n            r1 = _mm_stream_load_si128((__m128i *)(s + 1 * sizeof(__m128i)));\n            r2 = _mm_stream_load_si128((__m128i *)(s + 2 * sizeof(__m128i)));\n            r3 = _mm_stream_load_si128((__m128i *)(s + 3 * sizeof(__m128i)));\n            r4 = _mm_stream_load_si128((__m128i *)(s + 4 * sizeof(__m128i)));\n            r5 = _mm_stream_load_si128((__m128i *)(s + 5 * sizeof(__m128i)));\n            r6 = _mm_stream_load_si128((__m128i *)(s + 6 * sizeof(__m128i)));\n            r7 = _mm_stream_load_si128((__m128i *)(s + 7 * sizeof(__m128i)));\n            _mm_storeu_si128((__m128i *)(d + 0 * sizeof(__m128i)), r0);\n            _mm_storeu_si128((__m128i *)(d + 1 * sizeof(__m128i)), r1);\n            _mm_storeu_si128((__m128i *)(d + 2 * sizeof(__m128i)), r2);\n            _mm_storeu_si128((__m128i *)(d + 3 * sizeof(__m128i)), r3);\n            _mm_storeu_si128((__m128i *)(d + 4 * sizeof(__m128i)), r4);\n            _mm_storeu_si128((__m128i *)(d + 5 * sizeof(__m128i)), r5);\n            _mm_storeu_si128((__m128i *)(d + 6 * sizeof(__m128i)), r6);\n            _mm_storeu_si128((__m128i *)(d + 7 * sizeof(__m128i)), r7);\n            s += 8 * sizeof(__m128i);\n            d += 8 * sizeof(__m128i);\n            n -= 8 * sizeof(__m128i);\n        }\n        while (n >= sizeof(__m128i)) {\n            r0 = _mm_stream_load_si128((__m128i *)(s + 0 * sizeof(__m128i)));\n            _mm_storeu_si128((__m128i *)(d + 0 * sizeof(__m128i)), r0);\n            s += sizeof(__m128i);\n            d += sizeof(__m128i);\n            n -= sizeof(__m128i);\n        }\n    }\n    else { // or it IS aligned\n        __m128i r0, r1, r2, r3, r4, r5, r6, r7;\n        // unroll 8\n        while (n >= 8 * sizeof(__m128i)) {\n            r0 = _mm_stream_load_si128((__m128i *)(s + 0 * sizeof(__m128i)));\n            r1 = _mm_stream_load_si128((__m128i *)(s + 1 * sizeof(__m128i)));\n            r2 = _mm_stream_load_si128((__m128i *)(s + 2 * sizeof(__m128i)));\n            r3 = _mm_stream_load_si128((__m128i *)(s + 3 * sizeof(__m128i)));\n            r4 = _mm_stream_load_si128((__m128i *)(s + 4 * sizeof(__m128i)));\n            r5 = _mm_stream_load_si128((__m128i *)(s + 5 * sizeof(__m128i)));\n            r6 = _mm_stream_load_si128((__m128i *)(s + 6 * sizeof(__m128i)));\n            r7 = _mm_stream_load_si128((__m128i *)(s + 7 * sizeof(__m128i)));\n            _mm_stream_si128((__m128i *)(d + 0 * sizeof(__m128i)), r0);\n            _mm_stream_si128((__m128i *)(d + 1 * sizeof(__m128i)), r1);\n            _mm_stream_si128((__m128i *)(d + 2 * sizeof(__m128i)), r2);\n            _mm_stream_si128((__m128i *)(d + 3 * sizeof(__m128i)), r3);\n            _mm_stream_si128((__m128i *)(d + 4 * sizeof(__m128i)), r4);\n            _mm_stream_si128((__m128i *)(d + 5 * sizeof(__m128i)), r5);\n            _mm_stream_si128((__m128i *)(d + 6 * sizeof(__m128i)), r6);\n            _mm_stream_si128((__m128i *)(d + 7 * sizeof(__m128i)), r7);\n            s += 8 * sizeof(__m128i);\n            d += 8 * sizeof(__m128i);\n            n -= 8 * sizeof(__m128i);\n        }\n        while (n >= sizeof(__m128i)) {\n            r0 = _mm_stream_load_si128((__m128i *)(s + 0 * sizeof(__m128i)));\n            _mm_stream_si128((__m128i *)(d + 0 * sizeof(__m128i)), r0);\n            s += sizeof(__m128i);\n            d += sizeof(__m128i);\n            n -= sizeof(__m128i);\n        }\n    }\n\n    if (n)\n        memcpy(d, s, n);\n\n    // fencing because of NT stores\n    // potential optimization: issue only when NT stores are actually emitted\n    _mm_sfence();\n\n    return ret;\n}\n\n\nstatic void CopyPlane(uint8_t *dst, int dst_linesize,\n                    const uint8_t *src, int src_linesize,\n                    int bytewidth, int height)\n{\n    if (!dst || !src)\n        return;\n\n    for (;height > 0; height--) {\n        memcpy_uncached_load_sse41(dst, src, bytewidth);\n        dst += dst_linesize;\n        src += src_linesize;\n    }\n}\n\n\n// TODO use better criteria\nstatic intptr_t getHWAccelDevice(IDirect3D9* pDirect3D9)\n{\n    intptr_t result = D3DADAPTER_DEFAULT;\n    const auto count = pDirect3D9->GetAdapterCount();\n    if (count < 2)\n        return result;\n    UINT height{}, width{};\n    for (unsigned int i = 0; i < count; ++i)\n    {\n        D3DDISPLAYMODE d3ddm{};\n        if (SUCCEEDED(pDirect3D9->GetAdapterDisplayMode(i, &d3ddm))\n            && d3ddm.Height > height && d3ddm.Width > width)\n        {\n            result = i;\n            height = d3ddm.Height;\n            width = d3ddm.Width;\n        }\n    }\n\n    return result;\n}\n\n\n    /* define all the GUIDs used directly here,\n    to avoid problems with inconsistent dxva2api.h versions in mingw-w64 and different MSVC version */\n#include <initguid.h>\n\n// https://docs.microsoft.com/windows-hardware/drivers/display/providing-capabilities-for-video-decoding\n// https://gix.github.io/media-types/\n\nDEFINE_GUID(IID_IDirectXVideoDecoderService, 0xfc51a551, 0xd5e7, 0x11d9, 0xaf, 0x55, 0x00, 0x05, 0x4e, 0x43, 0xff, 0x02);\n\nDEFINE_GUID(DXVA2_ModeMPEG2_VLD, 0xee27417f, 0x5e28, 0x4e65, 0xbe, 0xea, 0x1d, 0x26, 0xb5, 0x08, 0xad, 0xc9);\nDEFINE_GUID(DXVA2_ModeMPEG2and1_VLD, 0x86695f12, 0x340e, 0x4f04, 0x9f, 0xd3, 0x92, 0x53, 0xdd, 0x32, 0x74, 0x60);\nDEFINE_GUID(DXVA2_ModeMPEG2_MoComp, 0xe6a9f44b, 0x61b0, 0x4563, 0x9e, 0xa4, 0x63, 0xd2, 0xa3, 0xc6, 0xfe, 0x66);\nDEFINE_GUID(DXVADDI_ModeMPEG2_IDCT, 0xbf22ad00, 0x03ea, 0x4690, 0x80, 0x77, 0x47, 0x33, 0x46, 0x20, 0x9b, 0x7e);\n\nDEFINE_GUID(DXVA2_ModeH264_E, 0x1b81be68, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\nDEFINE_GUID(DXVA2_ModeH264_F, 0x1b81be69, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\nDEFINE_GUID(DXVADDI_Intel_ModeH264_E, 0x604F8E68, 0x4951, 0x4C54, 0x88, 0xFE, 0xAB, 0xD2, 0x5C, 0x15, 0xB3, 0xD6);\n\nDEFINE_GUID(DXVADDI_ModeH264_A, 0x1b81be64, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\nDEFINE_GUID(DXVADDI_ModeH264_B, 0x1b81be65, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\nDEFINE_GUID(DXVADDI_ModeH264_C, 0x1b81be66, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\nDEFINE_GUID(DXVADDI_ModeH264_D, 0x1b81be67, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\n\nDEFINE_GUID(DXVA2_ModeVC1_D, 0x1b81beA3, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\nDEFINE_GUID(DXVA2_ModeVC1_D2010, 0x1b81beA4, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\n\nDEFINE_GUID(DXVA2_ModeHEVC_VLD_Main, 0x5b11d51b, 0x2f4c, 0x4452, 0xbc, 0xc3, 0x09, 0xf2, 0xa1, 0x16, 0x0c, 0xc0);\nDEFINE_GUID(DXVA2_ModeHEVC_VLD_Main10,0x107af0e0, 0xef1a,0x4d19,0xab,0xa8,0x67,0xa1,0x63,0x07,0x3d,0x13);\nDEFINE_GUID(DXVA2_ModeVP9_VLD_Profile0, 0x463707f8, 0xa1d0, 0x4585, 0x87, 0x6d, 0x83, 0xaa, 0x6d, 0x60, 0xb8, 0x9e);\nDEFINE_GUID(DXVA2_ModeVP9_VLD_10bit_Profile2, 0xa4c749ef, 0x6ecf, 0x48aa, 0x84, 0x48, 0x50, 0xa7, 0xa1, 0x16, 0x5f, 0xf7);\n\nDEFINE_GUID(DXVADDI_ModeVC1_A, 0x1b81beA0, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\nDEFINE_GUID(DXVADDI_ModeVC1_B, 0x1b81beA1, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\nDEFINE_GUID(DXVADDI_ModeVC1_C, 0x1b81beA2, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\n\nDEFINE_GUID(DXVADDI_ModeWMV8_A, 0x1b81be80, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\nDEFINE_GUID(DXVADDI_ModeWMV8_B, 0x1b81be81, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\n\nDEFINE_GUID(DXVADDI_ModeWMV9_A, 0x1b81be90, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\nDEFINE_GUID(DXVADDI_ModeWMV9_B, 0x1b81be91, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\nDEFINE_GUID(DXVADDI_ModeWMV9_C, 0x1b81be94, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\n\nDEFINE_GUID(DXVA2_NoEncrypt, 0x1b81beD0, 0xa0c7, 0x11d3, 0xb9, 0x84, 0x00, 0xc0, 0x4f, 0x2e, 0x73, 0xc5);\nDEFINE_GUID(GUID_NULL, 0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);\n\n//DEFINE_GUID(DXVA2_Unknown, 0xA74CCAE2, 0xF466, 0x45AE, 0x86, 0xF5, 0xAB, 0x8B, 0xE8, 0xAF, 0x84, 0x83);\n\ntypedef IDirect3D9* WINAPI pDirect3DCreate9(UINT);\ntypedef HRESULT WINAPI pCreateDeviceManager9(UINT *, IDirect3DDeviceManager9 **);\n\ntypedef struct dxva2_mode {\n    const GUID     *guid;\n    enum AVCodecID codec;\n} dxva2_mode;\n\nstatic const dxva2_mode dxva2_modes[] = {\n    /* MPEG-2 */\n    { &DXVA2_ModeMPEG2_VLD, AV_CODEC_ID_MPEG2VIDEO },\n    { &DXVA2_ModeMPEG2and1_VLD, AV_CODEC_ID_MPEG2VIDEO },\n\n    { &DXVA2_ModeMPEG2_MoComp, AV_CODEC_ID_MPEG2VIDEO },\n    { &DXVADDI_ModeMPEG2_IDCT, AV_CODEC_ID_MPEG2VIDEO },\n\n    /* H.264 */\n    { &DXVA2_ModeH264_F, AV_CODEC_ID_H264 },\n    { &DXVA2_ModeH264_E, AV_CODEC_ID_H264 },\n    /* Intel specific H.264 mode */\n    { &DXVADDI_Intel_ModeH264_E, AV_CODEC_ID_H264 },\n\n    { &DXVADDI_ModeH264_A, AV_CODEC_ID_H264 },\n    { &DXVADDI_ModeH264_B, AV_CODEC_ID_H264 },\n    { &DXVADDI_ModeH264_C, AV_CODEC_ID_H264 },\n    { &DXVADDI_ModeH264_D, AV_CODEC_ID_H264 },\n\n    /* VC-1 / WMV3 */\n    { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_VC1 },\n    { &DXVA2_ModeVC1_D2010, AV_CODEC_ID_WMV3 },\n    { &DXVA2_ModeVC1_D, AV_CODEC_ID_VC1 },\n    { &DXVA2_ModeVC1_D, AV_CODEC_ID_WMV3 },\n\n    { &DXVADDI_ModeVC1_A, AV_CODEC_ID_VC1 },\n    { &DXVADDI_ModeVC1_A, AV_CODEC_ID_WMV3 },\n    { &DXVADDI_ModeVC1_B, AV_CODEC_ID_VC1 },\n    { &DXVADDI_ModeVC1_B, AV_CODEC_ID_WMV3 },\n    { &DXVADDI_ModeVC1_C, AV_CODEC_ID_VC1 },\n    { &DXVADDI_ModeVC1_C, AV_CODEC_ID_WMV3 },\n\n\n    { &DXVADDI_ModeWMV8_A, AV_CODEC_ID_WMV3 },\n    { &DXVADDI_ModeWMV8_B, AV_CODEC_ID_WMV3 },\n    { &DXVADDI_ModeWMV9_A, AV_CODEC_ID_WMV3 },\n    { &DXVADDI_ModeWMV9_B, AV_CODEC_ID_WMV3 },\n    { &DXVADDI_ModeWMV9_C, AV_CODEC_ID_WMV3 },\n\n\n    /* HEVC/H.265 */\n    { &DXVA2_ModeHEVC_VLD_Main10,AV_CODEC_ID_HEVC }, // comes first\n    { &DXVA2_ModeHEVC_VLD_Main, AV_CODEC_ID_HEVC },\n\n    /* VP8/9 */\n    { &DXVA2_ModeVP9_VLD_10bit_Profile2, AV_CODEC_ID_VP9 },\n    { &DXVA2_ModeVP9_VLD_Profile0, AV_CODEC_ID_VP9 },\n\n    { NULL, AV_CODEC_ID_NONE },\n};\n\ntypedef struct surface_info {\n    int used;\n    uint64_t age;\n} surface_info;\n\ntypedef struct DXVA2Context {\n    HMODULE d3dlib;\n    HMODULE dxva2lib;\n\n    HANDLE  deviceHandle;\n\n    IDirect3D9                  *d3d9;\n    IDirect3DDevice9            *d3d9device;\n    IDirect3DDeviceManager9     *d3d9devmgr;\n    IDirectXVideoDecoderService *decoder_service;\n    IDirectXVideoDecoder        *decoder;\n\n    GUID                        decoder_guid;\n    DXVA2_ConfigPictureDecode   decoder_config;\n\n    LPDIRECT3DSURFACE9          *surfaces;\n    surface_info                *surface_infos;\n    uint32_t                    num_surfaces;\n    uint64_t                    surface_age;\n\n    AVFrame                     *tmp_frame;\n} DXVA2Context;\n\ntypedef struct DXVA2SurfaceWrapper {\n    DXVA2Context         *ctx;\n    LPDIRECT3DSURFACE9   surface;\n    IDirectXVideoDecoder *decoder;\n} DXVA2SurfaceWrapper;\n\nenum HWAccelID {\n    HWACCEL_NONE = 0,\n    HWACCEL_AUTO,\n    HWACCEL_VDPAU,\n    HWACCEL_DXVA2,\n    HWACCEL_VDA,\n    HWACCEL_VIDEOTOOLBOX,\n    HWACCEL_QSV,\n};\n\nstruct InputStream\n{\n    AVCodecContext* dec_ctx;\n    /* hwaccel options */\n    enum HWAccelID hwaccel_id;\n    intptr_t hwaccel_device;\n\n    /* hwaccel context */\n    enum HWAccelID active_hwaccel_id;\n    void* hwaccel_ctx;\n    void* hwaccel_context; // for DXVA2\n    enum AVPixelFormat hwaccel_pix_fmt;\n};\n\n\nstatic void dxva2_destroy_decoder(InputStream* ist)\n{\n    DXVA2Context *ctx = (DXVA2Context *)ist->hwaccel_ctx;\n\n    if (ctx->surfaces) {\n        for (int i = 0; i < ctx->num_surfaces; i++) {\n            if (ctx->surfaces[i])\n                IDirect3DSurface9_Release(ctx->surfaces[i]);\n        }\n    }\n    av_freep(&ctx->surfaces);\n    av_freep(&ctx->surface_infos);\n    ctx->num_surfaces = 0;\n    ctx->surface_age = 0;\n\n    if (ctx->decoder) {\n        ctx->decoder->Release();\n        ctx->decoder = NULL;\n    }\n}\n\nvoid dxva2_uninit(void* opaque)\n{\n    InputStream* ist = static_cast<InputStream*>(opaque);\n\n    DXVA2Context *ctx = (DXVA2Context *)ist->hwaccel_ctx;\n\n    if (ctx->decoder)\n        dxva2_destroy_decoder(ist);\n\n    if (ctx->decoder_service)\n        ctx->decoder_service->Release();\n\n    if (ctx->d3d9devmgr && ctx->deviceHandle != INVALID_HANDLE_VALUE)\n        ctx->d3d9devmgr->CloseDeviceHandle(ctx->deviceHandle);\n\n    if (ctx->d3d9devmgr)\n        ctx->d3d9devmgr->Release();\n\n    if (ctx->d3d9device)\n        IDirect3DDevice9_Release(ctx->d3d9device);\n\n    if (ctx->d3d9)\n        IDirect3D9_Release(ctx->d3d9);\n\n    if (ctx->d3dlib)\n        FreeLibrary(ctx->d3dlib);\n\n    if (ctx->dxva2lib)\n        FreeLibrary(ctx->dxva2lib);\n\n    av_frame_free(&ctx->tmp_frame);\n\n    av_freep(&ist->hwaccel_ctx);\n    av_freep(&ist->hwaccel_context);\n\n    delete ist;\n}\n\nstatic void dxva2_release_buffer(void *opaque, uint8_t *data)\n{\n    DXVA2SurfaceWrapper *w = (DXVA2SurfaceWrapper *)opaque;\n    DXVA2Context        *ctx = w->ctx;\n    int i;\n\n    for (i = 0; i < ctx->num_surfaces; i++) {\n        if (ctx->surfaces[i] == w->surface) {\n            ctx->surface_infos[i].used = 0;\n            break;\n        }\n    }\n    IDirect3DSurface9_Release(w->surface);\n    w->decoder->Release();\n    av_free(w);\n}\n\nstatic int dxva2_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)\n{\n    InputStream  *ist = (InputStream  *)s->opaque;\n    DXVA2Context *ctx = (DXVA2Context *)ist->hwaccel_ctx;\n    int i, old_unused = -1;\n    LPDIRECT3DSURFACE9 surface;\n    DXVA2SurfaceWrapper *w = NULL;\n\n    av_assert0(frame->format == AV_PIX_FMT_DXVA2_VLD);\n\n    for (i = 0; i < ctx->num_surfaces; i++) {\n        surface_info *info = &ctx->surface_infos[i];\n        if (!info->used && (old_unused == -1 || info->age < ctx->surface_infos[old_unused].age))\n            old_unused = i;\n    }\n    if (old_unused == -1) {\n        av_log(NULL, AV_LOG_ERROR, \"No free DXVA2 surface!\\n\");\n        return AVERROR(ENOMEM);\n    }\n    i = old_unused;\n\n    surface = ctx->surfaces[i];\n\n    w = (DXVA2SurfaceWrapper *)av_mallocz(sizeof(*w));\n    if (!w)\n        return AVERROR(ENOMEM);\n\n    frame->buf[0] = av_buffer_create((uint8_t*)surface, 0,\n        dxva2_release_buffer, w,\n        AV_BUFFER_FLAG_READONLY);\n    if (!frame->buf[0]) {\n        av_free(w);\n        return AVERROR(ENOMEM);\n    }\n\n    w->ctx = ctx;\n    w->surface = surface;\n    IDirect3DSurface9_AddRef(w->surface);\n    w->decoder = ctx->decoder;\n    w->decoder->AddRef();\n\n    ctx->surface_infos[i].used = 1;\n    ctx->surface_infos[i].age = ctx->surface_age++;\n\n    frame->data[3] = (uint8_t *)surface;\n\n    return 0;\n}\n\nstatic const auto CopyPlanePtr = (av_get_cpu_flags() & AV_CPU_FLAG_SSE4) ? CopyPlane : av_image_copy_plane;\n\nint dxva2_convert_data(IDirect3DSurface9* surface, AVFrame *tmp_frame, int width, int height)\n{\n    D3DSURFACE_DESC    surfaceDesc;\n    D3DLOCKED_RECT     LockedRect;\n    HRESULT            hr;\n    int                ret;\n\n    IDirect3DSurface9_GetDesc(surface, &surfaceDesc);\n\n    hr = IDirect3DSurface9_LockRect(surface, &LockedRect, NULL, D3DLOCK_READONLY);\n    if (FAILED(hr)) {\n        av_log(NULL, AV_LOG_ERROR, \"Unable to lock DXVA2 surface\\n\");\n        return AVERROR_UNKNOWN;\n    }\n\n    tmp_frame->width = width;\n    tmp_frame->height = height;\n    switch (surfaceDesc.Format)\n    {\n    case MKTAG('N', 'V', '1', '2'):\n        tmp_frame->format = AV_PIX_FMT_NV12;\n\n        ret = av_frame_get_buffer(tmp_frame, 32);\n        if (ret == 0)\n        {\n            CopyPlanePtr(tmp_frame->data[0], tmp_frame->linesize[0],\n                (uint8_t*)LockedRect.pBits,\n                LockedRect.Pitch, width, height);\n\n            CopyPlanePtr(tmp_frame->data[1], tmp_frame->linesize[1],\n                (uint8_t*)LockedRect.pBits + LockedRect.Pitch * surfaceDesc.Height,\n                LockedRect.Pitch, width, height / 2);\n        }\n        break;\n    case MKTAG('P', '0', '1', '0'):\n        tmp_frame->format = AV_PIX_FMT_P010;\n\n        ret = av_frame_get_buffer(tmp_frame, 32);\n        if (ret == 0)\n        {\n            CopyPlanePtr(tmp_frame->data[0], tmp_frame->linesize[0],\n                (uint8_t*)LockedRect.pBits,\n                LockedRect.Pitch, width * 2, height);\n\n            CopyPlanePtr(tmp_frame->data[1], tmp_frame->linesize[1],\n                (uint8_t*)LockedRect.pBits + LockedRect.Pitch * surfaceDesc.Height,\n                LockedRect.Pitch, width * 2, height / 2);\n        }\n        break;\n    case D3DFMT_YUY2:\n        tmp_frame->format = AV_PIX_FMT_YUYV422;\n\n        ret = av_frame_get_buffer(tmp_frame, 32);\n        if (ret == 0)\n        {\n            CopyPlanePtr(tmp_frame->data[0], tmp_frame->linesize[0],\n                (uint8_t*)LockedRect.pBits,\n                LockedRect.Pitch, width * 2, height);\n        }\n        break;\n    default: // IMC3\n        tmp_frame->format = AV_PIX_FMT_YUV420P;\n\n        ret = av_frame_get_buffer(tmp_frame, 32);\n        if (ret == 0)\n        {\n            uint8_t* pU = (uint8_t*)LockedRect.pBits + (((height + 15) & ~15) * LockedRect.Pitch);\n            uint8_t* pV = (uint8_t*)LockedRect.pBits + (((((height * 3) / 2) + 15) & ~15) * LockedRect.Pitch);\n\n            CopyPlanePtr(tmp_frame->data[0], tmp_frame->linesize[0],\n                (uint8_t*)LockedRect.pBits,\n                LockedRect.Pitch, width, height);\n\n            CopyPlanePtr(tmp_frame->data[1], tmp_frame->linesize[1],\n                pU, LockedRect.Pitch, width / 2, height / 2);\n\n            CopyPlanePtr(tmp_frame->data[2], tmp_frame->linesize[2],\n                pV, LockedRect.Pitch, width / 2, height / 2);\n        }\n    }\n\n    IDirect3DSurface9_UnlockRect(surface);\n\n    return ret;\n}\n\nint dxva2_retrieve_data(AVCodecContext *s, AVFrame *frame)\n{\n    LPDIRECT3DSURFACE9 surface = (LPDIRECT3DSURFACE9)frame->data[3];\n    InputStream        *ist = (InputStream *)s->opaque;\n    DXVA2Context       *ctx = (DXVA2Context *)ist->hwaccel_ctx;\n\n    int ret = dxva2_convert_data(surface, ctx->tmp_frame, frame->width, frame->height);\n    if (ret < 0)\n        return ret;\n\n    ret = av_frame_copy_props(ctx->tmp_frame, frame);\n    if (ret < 0)\n    {\n        av_frame_unref(ctx->tmp_frame);\n        return ret;\n    }\n\n    av_frame_unref(frame);\n    av_frame_move_ref(frame, ctx->tmp_frame);\n\n    return 0;\n}\n\nstatic int dxva2_alloc(AVCodecContext *s)\n{\n    InputStream *ist = (InputStream *)s->opaque;\n    int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;\n    DXVA2Context *ctx;\n    pDirect3DCreate9      *createD3D = NULL;\n    pCreateDeviceManager9 *createDeviceManager = NULL;\n    HRESULT hr;\n    D3DPRESENT_PARAMETERS d3dpp = { 0 };\n    unsigned resetToken = 0;\n    UINT adapter = D3DADAPTER_DEFAULT;\n\n    ctx = (DXVA2Context *)av_mallocz(sizeof(*ctx));\n    if (!ctx)\n    {\n        delete ist;\n        return AVERROR(ENOMEM);\n    }\n    ctx->deviceHandle = INVALID_HANDLE_VALUE;\n\n    ist->hwaccel_ctx = ctx;\n\n    ctx->d3dlib = LoadLibraryW(L\"d3d9.dll\");\n    if (!ctx->d3dlib) {\n        av_log(NULL, loglevel, \"Failed to load D3D9 library\\n\");\n        goto fail;\n    }\n    ctx->dxva2lib = LoadLibraryW(L\"dxva2.dll\");\n    if (!ctx->dxva2lib) {\n        av_log(NULL, loglevel, \"Failed to load DXVA2 library\\n\");\n        goto fail;\n    }\n\n    createD3D = (pDirect3DCreate9 *)GetProcAddress(ctx->d3dlib, \"Direct3DCreate9\");\n    if (!createD3D) {\n        av_log(NULL, loglevel, \"Failed to locate Direct3DCreate9\\n\");\n        goto fail;\n    }\n    createDeviceManager = (pCreateDeviceManager9 *)GetProcAddress(ctx->dxva2lib, \"DXVA2CreateDirect3DDeviceManager9\");\n    if (!createDeviceManager) {\n        av_log(NULL, loglevel, \"Failed to locate DXVA2CreateDirect3DDeviceManager9\\n\");\n        goto fail;\n    }\n\n    ctx->d3d9 = createD3D(D3D_SDK_VERSION);\n    if (!ctx->d3d9) {\n        av_log(NULL, loglevel, \"Failed to create IDirect3D object\\n\");\n        goto fail;\n    }\n\n    if (ist->hwaccel_device) {\n        adapter = ist->hwaccel_device;\n    }\n    else {\n        adapter = getHWAccelDevice(ctx->d3d9);\n    }\n    av_log(NULL, AV_LOG_INFO, \"Using HWAccel device %d\\n\", adapter);\n\n    //IDirect3D9_GetAdapterDisplayMode(ctx->d3d9, adapter, &d3ddm);\n    d3dpp.Windowed = TRUE;\n    d3dpp.BackBufferWidth = GetSystemMetrics(SM_CXSCREEN);\n    d3dpp.BackBufferHeight = GetSystemMetrics(SM_CYSCREEN);\n    d3dpp.BackBufferCount = 1;\n    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;// d3ddm.Format;\n    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;\n    d3dpp.Flags = D3DPRESENTFLAG_VIDEO;\n\n    d3dpp.Windowed = TRUE;\n    d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;\n    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;\n\n\n    hr = IDirect3D9_CreateDevice(ctx->d3d9, adapter, D3DDEVTYPE_HAL, GetDesktopWindow(),\n        D3DCREATE_SOFTWARE_VERTEXPROCESSING | D3DCREATE_MULTITHREADED | D3DCREATE_FPU_PRESERVE,\n        &d3dpp, &ctx->d3d9device);\n    if (FAILED(hr)) {\n        av_log(NULL, loglevel, \"Failed to create Direct3D device\\n\");\n        goto fail;\n    }\n\n    hr = createDeviceManager(&resetToken, &ctx->d3d9devmgr);\n    if (FAILED(hr)) {\n        av_log(NULL, loglevel, \"Failed to create Direct3D device manager\\n\");\n        goto fail;\n    }\n\n    hr = ctx->d3d9devmgr->ResetDevice(ctx->d3d9device, resetToken);\n    if (FAILED(hr)) {\n        av_log(NULL, loglevel, \"Failed to bind Direct3D device to device manager\\n\");\n        goto fail;\n    }\n\n    hr = ctx->d3d9devmgr->OpenDeviceHandle(&ctx->deviceHandle);\n    if (FAILED(hr)) {\n        av_log(NULL, loglevel, \"Failed to open device handle\\n\");\n        goto fail;\n    }\n\n    hr = ctx->d3d9devmgr->GetVideoService(ctx->deviceHandle, IID_IDirectXVideoDecoderService, (void **)&ctx->decoder_service);\n    if (FAILED(hr)) {\n        av_log(NULL, loglevel, \"Failed to create IDirectXVideoDecoderService\\n\");\n        goto fail;\n    }\n\n    ctx->tmp_frame = av_frame_alloc();\n    if (!ctx->tmp_frame)\n        goto fail;\n\n    s->hwaccel_context = av_mallocz(sizeof(struct dxva_context));\n    if (!s->hwaccel_context)\n        goto fail;\n\n    ist->hwaccel_context = s->hwaccel_context;\n\n    return 0;\nfail:\n    dxva2_uninit(ist);\n    return AVERROR(EINVAL);\n}\n\nstatic int dxva2_get_decoder_configuration(AVCodecContext *s, const GUID *device_guid,\n    const DXVA2_VideoDesc *desc,\n    DXVA2_ConfigPictureDecode *config)\n{\n    InputStream  *ist = (InputStream *)s->opaque;\n    int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;\n    DXVA2Context *ctx = (DXVA2Context *)ist->hwaccel_ctx;\n    unsigned cfg_count = 0, best_score = 0;\n    DXVA2_ConfigPictureDecode *cfg_list = NULL;\n    DXVA2_ConfigPictureDecode best_cfg = { { 0 } };\n    HRESULT hr;\n    int i;\n\n    hr = ctx->decoder_service->GetDecoderConfigurations(*device_guid, desc, NULL, &cfg_count, &cfg_list);\n    if (FAILED(hr)) {\n        av_log(NULL, loglevel, \"Unable to retrieve decoder configurations\\n\");\n        return AVERROR(EINVAL);\n    }\n\n    for (i = 0; i < cfg_count; i++) {\n        DXVA2_ConfigPictureDecode *cfg = &cfg_list[i];\n\n        unsigned score;\n        if (cfg->ConfigBitstreamRaw == 1)\n            score = 1;\n        else if (s->codec_id == AV_CODEC_ID_H264 && cfg->ConfigBitstreamRaw == 2)\n            score = 2;\n        else\n            continue;\n        if (IsEqualGUID(cfg->guidConfigBitstreamEncryption, DXVA2_NoEncrypt))\n            score += 16;\n        if (score > best_score) {\n            best_score = score;\n            best_cfg = *cfg;\n        }\n    }\n    CoTaskMemFree(cfg_list);\n\n    if (!best_score) {\n        av_log(NULL, loglevel, \"No valid decoder configuration available\\n\");\n        return AVERROR(EINVAL);\n    }\n\n    *config = best_cfg;\n    return 0;\n}\n\nstatic bool isMoreThan8BytesFmt(AVPixelFormat f)\n{\n    if (auto d = av_pix_fmt_desc_get(f))\n    {\n        for (int i = 0; i < d->nb_components; ++i)\n            if (d->comp[i].depth > 8)\n                return true;\n    }\n    return false;\n}\n\nstatic int dxva2_create_decoder(AVCodecContext *s)\n{\n    InputStream  *ist = (InputStream *)s->opaque;\n    int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE : AV_LOG_ERROR;\n    DXVA2Context *ctx = (DXVA2Context *)ist->hwaccel_ctx;\n    struct dxva_context *dxva_ctx = (dxva_context *)s->hwaccel_context;\n    GUID *guid_list = NULL;\n    unsigned guid_count = 0, i, j;\n    GUID device_guid = GUID_NULL;\n    D3DFORMAT target_format = D3DFMT_UNKNOWN;\n    DXVA2_VideoDesc desc = { 0 };\n    DXVA2_ConfigPictureDecode config;\n    HRESULT hr;\n    int surface_alignment;\n    int ret;\n\n    hr = ctx->decoder_service->GetDecoderDeviceGuids(&guid_count, &guid_list);\n    if (FAILED(hr)) {\n        av_log(NULL, loglevel, \"Failed to retrieve decoder device GUIDs\\n\");\n        goto fail;\n    }\n\n    const bool is10format = isMoreThan8BytesFmt(\n        (s->sw_pix_fmt == AV_PIX_FMT_NONE)? s->pix_fmt : s->sw_pix_fmt);\n\n    for (i = 0; dxva2_modes[i].guid; i++) {\n        D3DFORMAT *target_list = NULL;\n        unsigned target_count = 0;\n        const dxva2_mode *mode = &dxva2_modes[i];\n        if (mode->codec != s->codec_id)\n            continue;\n\n        for (j = 0; j < guid_count; j++) {\n            if (IsEqualGUID(*mode->guid, guid_list[j]))\n                break;\n        }\n        if (j == guid_count)\n            continue;\n\n        hr = ctx->decoder_service->GetDecoderRenderTargets(*mode->guid, &target_count, &target_list);\n        if (FAILED(hr)) {\n            continue;\n        }\n\n        for (j = 0; j < target_count; j++) {\n            const D3DFORMAT format = target_list[j];\n            if (is10format? (format == MKTAG('P', '0', '1', '0'))\n                    : (format == MKTAG('N', 'V', '1', '2') || format == MKTAG('I', 'M', 'C', '3'))) {\n                target_format = format;\n                break;\n            }\n        }\n        CoTaskMemFree(target_list);\n        if (target_format) {\n            device_guid = *mode->guid;\n            break;\n        }\n    }\n    CoTaskMemFree(guid_list);\n\n    if (IsEqualGUID(device_guid, GUID_NULL)) {\n        av_log(NULL, loglevel, \"No decoder device for codec found\\n\");\n        goto fail;\n    }\n\n    desc.SampleWidth = s->coded_width;\n    desc.SampleHeight = s->coded_height;\n    desc.Format = target_format;\n\n    ret = dxva2_get_decoder_configuration(s, &device_guid, &desc, &config);\n    if (ret < 0) {\n        goto fail;\n    }\n\n    /* decoding MPEG-2 requires additional alignment on some Intel GPUs,\n    but it causes issues for H.264 on certain AMD GPUs..... */\n    if (s->codec_id == AV_CODEC_ID_MPEG2VIDEO)\n        surface_alignment = 32;\n    /* the HEVC DXVA2 spec asks for 128 pixel aligned surfaces to ensure\n    all coding features have enough room to work with */\n    else if (s->codec_id == AV_CODEC_ID_HEVC)\n        surface_alignment = 128;\n    else\n        surface_alignment = 16;\n\n    /* 4 base work surfaces */\n    //ctx->num_surfaces = 4;\n    ctx->num_surfaces = 4 + 3; // two video queue elements and one cached by view\n\n    /* add surfaces based on number of possible refs */\n    if (s->codec_id == AV_CODEC_ID_H264 || s->codec_id == AV_CODEC_ID_HEVC)\n        ctx->num_surfaces += 16;\n    else if (s->codec_id == AV_CODEC_ID_VP9)\n        ctx->num_surfaces += 8;\n    else\n        ctx->num_surfaces += 2;\n\n    /* add extra surfaces for frame threading */\n    if (s->active_thread_type & FF_THREAD_FRAME)\n        ctx->num_surfaces += s->thread_count;\n\n    ctx->surfaces = (LPDIRECT3DSURFACE9 *)av_mallocz(ctx->num_surfaces * sizeof(*ctx->surfaces));\n    ctx->surface_infos = (surface_info *)av_mallocz(ctx->num_surfaces * sizeof(*ctx->surface_infos));\n\n    if (!ctx->surfaces || !ctx->surface_infos) {\n        av_log(NULL, loglevel, \"Unable to allocate surface arrays\\n\");\n        goto fail;\n    }\n\n    hr = ctx->decoder_service->CreateSurface(FFALIGN(s->coded_width, surface_alignment),\n        FFALIGN(s->coded_height, surface_alignment),\n        ctx->num_surfaces - 1,\n        target_format, D3DPOOL_DEFAULT, 0,\n        DXVA2_VideoDecoderRenderTarget,\n        ctx->surfaces, NULL);\n    if (FAILED(hr)) {\n        av_log(NULL, loglevel, \"Failed to create %d video surfaces\\n\", ctx->num_surfaces);\n        goto fail;\n    }\n\n    hr = ctx->decoder_service->CreateVideoDecoder(device_guid,\n        &desc, &config, ctx->surfaces,\n        ctx->num_surfaces, &ctx->decoder);\n    if (FAILED(hr)) {\n        av_log(NULL, loglevel, \"Failed to create DXVA2 video decoder\\n\");\n        goto fail;\n    }\n\n    ctx->decoder_guid = device_guid;\n    ctx->decoder_config = config;\n\n    dxva_ctx->cfg = &ctx->decoder_config;\n    dxva_ctx->decoder = ctx->decoder;\n    dxva_ctx->surface = ctx->surfaces;\n    dxva_ctx->surface_count = ctx->num_surfaces;\n\n#ifdef FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO\n    if (IsEqualGUID(ctx->decoder_guid, DXVADDI_Intel_ModeH264_E))\n        dxva_ctx->workaround |= FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO;\n#endif\n\n    return 0;\nfail:\n    dxva2_destroy_decoder(ist);\n    return AVERROR(EINVAL);\n}\n\nstatic AVPixelFormat GetHwFormat(AVCodecContext* s, const AVPixelFormat* pix_fmts)\n{\n    auto* ist = static_cast<InputStream*>(s->opaque);\n    ist->active_hwaccel_id = HWACCEL_DXVA2;\n    ist->hwaccel_pix_fmt = AV_PIX_FMT_DXVA2_VLD;\n    return ist->hwaccel_pix_fmt;\n}\n\nint dxva2_init(AVCodecContext *s)\n{\n    const int loglevel = AV_LOG_VERBOSE;\n\n    bool ok = false;\n    for (const dxva2_mode *mode = dxva2_modes; mode->guid; mode++)\n    {\n        if (mode->codec == s->codec_id)\n        {\n            ok = true;\n            break;\n        }\n    }\n    if (!ok)\n    {\n        av_log(NULL, loglevel, \"Unsupported codec for DXVA2 HWAccel: %d\\n\", s->codec_id);\n        return AVERROR(EINVAL);\n    }\n\n    if (s->codec_id == AV_CODEC_ID_H264 &&\n        (s->profile & ~AV_PROFILE_H264_CONSTRAINED) > AV_PROFILE_H264_HIGH) {\n        av_log(NULL, loglevel, \"Unsupported H.264 profile for DXVA2 HWAccel: %d\\n\", s->profile);\n        return AVERROR(EINVAL);\n    }\n\n    if (s->codec_id == AV_CODEC_ID_HEVC &&\n        s->profile != AV_PROFILE_HEVC_MAIN && s->profile != AV_PROFILE_HEVC_MAIN_10) {\n        av_log(NULL, loglevel, \"Unsupported HEVC profile for DXVA2 HWAccel: %d\\n\", s->profile);\n        return AVERROR(EINVAL);\n    }\n\n    auto ist = new InputStream();\n    ist->hwaccel_id = HWACCEL_AUTO;\n    ist->dec_ctx = s;\n    s->opaque = ist;\n\n    int ret;\n\n    if (!ist->hwaccel_ctx) {\n        ret = dxva2_alloc(s);\n        if (ret < 0)\n        {\n            s->opaque = nullptr;\n            return ret;\n        }\n    }\n\n    DXVA2Context *ctx = (DXVA2Context *)ist->hwaccel_ctx;\n\n    if (ctx->decoder)\n        dxva2_destroy_decoder(ist);\n\n    ret = dxva2_create_decoder(s);\n    if (ret < 0) {\n        av_log(NULL, loglevel, \"Error creating the DXVA2 decoder\\n\");\n        dxva2_uninit(ist);\n        s->opaque = nullptr;\n        return ret;\n    }\n\n    s->get_buffer2 = dxva2_get_buffer;\n    s->get_format = GetHwFormat;\n\n    return 0;\n}\n\n\nIDirect3DDevice9* get_device(AVCodecContext *s)\n{\n    InputStream  *ist = (InputStream *)s->opaque;\n    DXVA2Context *ctx = (DXVA2Context *)ist->hwaccel_ctx;\n    return ctx->d3d9device;\n}\n\n#endif // _WIN32\n"
  },
  {
    "path": "video/ffmpeg_dxva2.h",
    "content": "#pragma once\n\n/*\n * This file is part of FFmpeg.\n *\n * FFmpeg is free software; you can redistribute it and/or\n * modify it under the terms of the GNU Lesser General Public\n * License as published by the Free Software Foundation; either\n * version 2.1 of the License, or (at your option) any later version.\n *\n * FFmpeg is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\n * Lesser General Public License for more details.\n *\n * You should have received a copy of the GNU Lesser General Public\n * License along with FFmpeg; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\n */\n\n#ifdef _WIN32\n\ntypedef struct AVCodecContext AVCodecContext;\ntypedef struct AVFrame AVFrame;\n\ntypedef struct IDirect3DDevice9 IDirect3DDevice9;\ntypedef struct IDirect3DSurface9 IDirect3DSurface9;\n\nint dxva2_init(AVCodecContext *s);\nvoid dxva2_uninit(void* ist);\nint dxva2_convert_data(IDirect3DSurface9* surface, AVFrame *tmp_frame, int width, int height);\nint dxva2_retrieve_data(AVCodecContext *s, AVFrame *frame);\n\nIDirect3DDevice9* get_device(AVCodecContext *s);\n\n#endif // _WIN32\n"
  },
  {
    "path": "video/ffmpegdecoder.cpp",
    "content": "﻿#include \"ffmpegdecoder.h\"\n\n#include <climits>\n#include <cstdint>\n\n#include \"makeguard.h\"\n#include \"interlockedadd.h\"\n#include \"subtitles.h\"\n#include \"decoderiocontext.h\"\n\n#include <boost/chrono.hpp>\n#include <memory>\n#include <utility>\n#include <algorithm>\n#include <tuple>\n\n#include <boost/algorithm/string/predicate.hpp>\n#include <boost/algorithm/string.hpp>\n#include <boost/log/trivial.hpp>\n\n\nextern \"C\"\n{\n#include \"libavutil/pixdesc.h\"\n#include \"libavdevice/avdevice.h\"\n}\n\n#ifdef _WIN32\n#include <ws2tcpip.h>\n#define USE_HWACCEL\n#else\n#include <arpa/inet.h>\n#include <netdb.h>\n#endif\n\n// http://stackoverflow.com/questions/34602561\n#ifdef USE_HWACCEL\n#include \"ffmpeg_dxva2.h\"\n#endif\n\nnamespace\n{\n\nstatic std::vector<std::string> resolveHostnameToIPs(const std::string& hostname)\n{\n    std::vector<std::string> result;\n    addrinfo hints = {};\n    hints.ai_family = AF_INET; // return IPv4 only\n    hints.ai_socktype = SOCK_STREAM;\n    hints.ai_protocol = IPPROTO_TCP;\n\n    addrinfo* res = nullptr;\n    if (getaddrinfo(hostname.c_str(), nullptr, &hints, &res) != 0)\n        return result;\n\n    char ipStr[INET6_ADDRSTRLEN] = {0};\n    for (addrinfo* it = res; it != nullptr; it = it->ai_next)\n    {\n        void* addr = nullptr;\n        if (it->ai_family == AF_INET)\n        {\n            sockaddr_in* sa = reinterpret_cast<sockaddr_in*>(it->ai_addr);\n            addr = &sa->sin_addr;\n        }\n        //else if (it->ai_family == AF_INET6)\n        //{\n        //    sockaddr_in6* sa6 = reinterpret_cast<sockaddr_in6*>(it->ai_addr);\n        //    addr = &sa6->sin6_addr;\n        //}\n        else\n        {\n            continue;\n        }\n\n        if (inet_ntop(it->ai_family, addr, ipStr, sizeof(ipStr)))\n        {\n            result.emplace_back(ipStr);\n        }\n    }\n\n    freeaddrinfo(res);\n    return result;\n}\n\nvoid FreeVideoCodecContext(AVCodecContext*& videoCodecContext)\n{\n#ifdef USE_HWACCEL\n    if (videoCodecContext != nullptr)\n    {\n        if (auto stream = videoCodecContext->opaque)\n        {\n            videoCodecContext->opaque = nullptr;\n            avcodec_free_context(&videoCodecContext);\n            dxva2_uninit(stream);\n            return;\n        }\n    }\n#endif\n\n    // Close the codec\n    avcodec_free_context(&videoCodecContext);\n}\n\n\ninline void Shutdown(const std::unique_ptr<boost::thread>& th)\n{\n    if (th)\n    {\n        th->interrupt();\n        th->join();\n    }\n}\n\nint ThisThreadInterruptionRequested(void* ptr)\n{\n    boost::atomic_bool* flag = static_cast<boost::atomic_bool*>(ptr);\n    return static_cast<int>(*flag || boost::this_thread::interruption_requested());\n}\n\nint g_lastHttpCode = 0;\nstd::string g_lastLocationHttpHeader;\nboost::atomic_bool* g_interruptionRequestedFlag = nullptr;\nvoid log_callback(void *ptr, int level, const char *fmt, va_list vargs)\n{\n    if (level <= AV_LOG_ERROR)\n    {\n        char buffer[4096];\n        int length = vsnprintf(buffer, sizeof(buffer), fmt, vargs);\n        if (length > 0)\n        {\n            for (; length > 0 && (isspace(static_cast<unsigned char>(buffer[length - 1])) != 0); --length) {\n                ;\n            }\n            buffer[length] = '\\0';\n            CHANNEL_LOG(ffmpeg_internal) << buffer;\n        }\n    }\n    else if (const auto interruptionRequestedFlag = g_interruptionRequestedFlag)\n    {\n        if (strcmp(fmt, \"http_code=%d\\n\") == 0)\n        {\n            g_lastHttpCode = va_arg(vargs, int);\n        }\n        else if (g_lastHttpCode == 302 && g_lastLocationHttpHeader.empty()\n            && strcmp(fmt, \"header='%s'\\n\") == 0)\n        {\n            auto header = va_arg(vargs, const char*);\n            if (header != nullptr && strncmp(\"Location: \", header, 10) == 0)\n            {\n                g_lastLocationHttpHeader = header + 10;\n                *interruptionRequestedFlag = true;\n            }\n        }\n    }\n}\n\n}  // namespace\n\nnamespace channel_logger\n{\n\nusing boost::log::keywords::channel;\n\nChannelLogger\n    ffmpeg_closing(channel = \"ffmpeg_closing\"),\n    ffmpeg_opening(channel = \"ffmpeg_opening\"),\n    ffmpeg_pause(channel = \"ffmpeg_pause\"),\n    ffmpeg_seek(channel = \"ffmpeg_seek\"),\n    ffmpeg_sync(channel = \"ffmpeg_sync\"),\n    ffmpeg_threads(channel = \"ffmpeg_threads\"),\n    ffmpeg_volume(channel = \"ffmpeg_volume\"),\n    ffmpeg_internal(channel = \"ffmpeg_internal\");\n\n} // namespace channel_logger\n\nstd::unique_ptr<IFrameDecoder> GetFrameDecoder(std::unique_ptr<IAudioPlayer> audioPlayer)\n{\n    return std::unique_ptr<IFrameDecoder>(new FFmpegDecoder(std::move(audioPlayer)));\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\nFFmpegDecoder::FFmpegDecoder(std::unique_ptr<IAudioPlayer> audioPlayer)\n    : m_frameListener(nullptr),\n      m_decoderListener(nullptr),\n      m_audioSettings(48000, 2, AV_SAMPLE_FMT_S16),\n      m_pixelFormat(AV_PIX_FMT_YUV420P),\n      m_allowDirect3dData(false),\n      m_audioPlayer(std::move(audioPlayer)),\n      m_hwAccelerated(true)\n{\n    av_log_set_level(AV_LOG_ERROR);\n    av_log_set_callback(log_callback);\n\n    m_audioPlayer->SetCallback(this);\n\n    resetVariables();\n\n    // init codecs\n#if ( LIBAVFORMAT_VERSION_INT <= AV_VERSION_INT(58,9,100) )\n    avcodec_register_all();\n    av_register_all();\n#endif\n\n    avdevice_register_all();\n\n    avformat_network_init();\n}\n\nFFmpegDecoder::~FFmpegDecoder() { close(); }\n\nvoid FFmpegDecoder::resetVariables()\n{\n    m_videoCodec = nullptr;\n    m_formatContexts.clear();\n    m_formatContextInterrupts.clear();\n    m_videoCodecContext = nullptr;\n    m_audioCodecContext = nullptr;\n    m_audioSwrContext = nullptr;\n    m_videoStream = nullptr;\n    m_audioStream = nullptr;\n\n    m_startTime = 0;\n    m_currentTime = 0;\n    m_duration = 0;\n\n    m_prevTime = AV_NOPTS_VALUE;\n\n    m_imageCovertContext = nullptr;\n\n    m_audioPTS = 0;\n\n    m_frameDisplayingRequested = false;\n\n    ++m_generation;\n\n    m_isPaused = false;\n\n    m_seekDuration = AV_NOPTS_VALUE;\n    m_videoResetDuration = AV_NOPTS_VALUE;\n\n    m_seekRendezVous.count = 0;\n    m_videoResetRendezVous.count = 0;\n\n    m_videoResetting = false;\n\n    m_videoStartClock = VIDEO_START_CLOCK_NOT_INITIALIZED;\n\n    m_isVideoSeekingWhilePaused = false;\n\n    m_isPlaying = false;\n\n    m_audioPaused = false;\n    m_audioIndices.clear();\n\n    {\n        boost::lock_guard<boost::mutex> locker(m_addIntervalMutex);\n        m_subtitleItems.clear();\n    }\n\n    m_subtitleIdx = -1;\n    m_addIntervalCallback = {};\n\n    m_subtitlesCodecContext = nullptr;\n\n    m_speedRational = { 1, 1 };\n\n    CHANNEL_LOG(ffmpeg_closing) << \"Variables reset\";\n}\n\nvoid FFmpegDecoder::close()\n{\n    CHANNEL_LOG(ffmpeg_closing) << \"Start file closing\";\n\n    CHANNEL_LOG(ffmpeg_closing) << \"Aborting threads\";\n    // controls other threads, hence stop first\n    for (auto& mainParseThread : m_mainParseThreads)\n    {\n        Shutdown(mainParseThread);\n    }\n    Shutdown(m_mainVideoThread);\n    Shutdown(m_mainAudioThread);\n    Shutdown(m_mainDisplayThread);\n\n    m_audioPlayer->Close();\n\n    if (m_frameListener != nullptr) {\n        m_frameListener->decoderClosing();\n    }\n\n    closeProcessing();\n\n    if (m_decoderListener != nullptr) {\n        m_decoderListener->playingFinished();\n    }\n}\n\nvoid FFmpegDecoder::closeProcessing()\n{\n    m_audioPacketsQueue.clear();\n    m_videoPacketsQueue.clear();\n\n    CHANNEL_LOG(ffmpeg_closing) << \"Closing old vars\";\n\n    m_mainVideoThread.reset();\n    m_mainAudioThread.reset();\n    m_mainParseThreads.clear();\n    m_mainDisplayThread.reset();\n\n    // Free videoFrames\n    {\n        boost::lock_guard<boost::mutex> locker(m_videoFramesMutex);\n        m_videoFramesQueue.clear();\n    }\n\n    sws_freeContext(m_imageCovertContext);\n\n    if (m_audioSwrContext != nullptr)\n    {\n        swr_free(&m_audioSwrContext);\n    }\n\n    FreeVideoCodecContext(m_videoCodecContext);\n\n    // Close the audio codec\n    avcodec_free_context(&m_audioCodecContext);\n\n    avcodec_free_context(&m_subtitlesCodecContext);\n\n    bool isFileReallyClosed = false;\n\n    // Close video file\n    for (auto& formatContext : m_formatContexts)\n        if (formatContext != nullptr)\n        {\n            avformat_close_input(&formatContext);\n            isFileReallyClosed = true;\n        }\n\n    m_ioCtx.reset();\n\n    CHANNEL_LOG(ffmpeg_closing) << \"Old file closed\";\n\n    resetVariables();\n\n    if (m_decoderListener != nullptr) {\n        m_decoderListener->decoderClosed(isFileReallyClosed);\n    }\n}\n\nconst char szUserAgent[] = \"User-Agent: Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36\";\n\nbool FFmpegDecoder::openUrls(std::initializer_list<std::string> urls, const std::string& inputFormat, bool useHHO)\n{\n    close();\n\n    m_formatContextInterrupts = std::vector<boost::atomic_bool>(urls.size());\n    for (auto& elem : m_formatContextInterrupts) {\n        elem.store(false);\n    }\n\n    for (auto url : urls)\n    {\n        const auto interruptionRequestedFlag = &m_formatContextInterrupts.at(m_formatContexts.size());\n\n        auto iformat = inputFormat.empty() ? nullptr : av_find_input_format(inputFormat.c_str());\n\n        int redirectsLeft = 10;\n\n        for (;;)\n        {\n            std::vector<std::string> finalUrls{ url };\n            std::string hostname;\n\n            const bool isHttps = boost::starts_with(url, \"https://\");\n            if (isHttps)\n            {\n                if (useHHO)\n                {\n                    const auto pos = 8; // Move past \"://\"\n                    size_t endPos = url.find_first_of(\":/\", pos);\n                    if (endPos != std::string::npos) {\n                        hostname = url.substr(pos, endPos - pos);\n                        auto ips = resolveHostnameToIPs(hostname);\n                        if (!ips.empty()) {\n                            finalUrls.clear();\n                            for (const auto& ip : ips)\n                            {\n                                std::string urlWithIp = url.substr(0, pos) + ip + url.substr(endPos);\n                                finalUrls.push_back(urlWithIp);\n                            }\n                        }\n                    }\n                }\n            }\n\n            // Open video file\n\n            g_lastLocationHttpHeader.clear();\n            g_lastHttpCode = 0;\n            g_interruptionRequestedFlag = interruptionRequestedFlag;\n            AVFormatContext* formatContext = nullptr;\n            int error = -1;\n            for (const auto& finalUrl : finalUrls)\n            {\n                AVDictionary* streamOpts = nullptr;\n                auto avOptionsGuard = MakeGuard(&streamOpts, av_dict_free);\n                av_dict_set(&streamOpts, \"rw_timeout\", \"5000000\", 0); // 5 seconds I/O timeout.\n                if (isHttps || boost::starts_with(url, \"http://\")) // seems to be a bug\n                {\n                    av_dict_set(&streamOpts, \"timeout\", \"5000000\", 0); // 5 seconds tcp timeout.\n                }\n                if (useHHO && !hostname.empty())\n                {\n                    CHANNEL_LOG(ffmpeg_opening) << \"Opening using a HHO Host: \" << hostname << \" URL: \" << url;\n                    av_dict_set(&streamOpts, \"headers\", (\"Host: \" + hostname + \"\\r\\n\" + szUserAgent).c_str(), 0);\n                }\n                else\n                {\n                    av_dict_set(&streamOpts, \"headers\", szUserAgent, 0);\n                }\n\n                if (iformat)\n                {\n                    av_dict_set(&streamOpts, \"rtbufsize\", \"15000000\", 0); // https://superuser.com/questions/1158820/ffmpeg-real-time-buffer-issue-rtbufsize-parameter\n                }\n                if (iformat ? (iformat->name != nullptr && strcmp(iformat->name, \"sdp\") == 0) : boost::iends_with(url, \".sdp\"))\n                {\n                    av_dict_set(&streamOpts, \"protocol_whitelist\", \"file,http,https,tls,rtp,tcp,udp,crypto,httpproxy,data\", 0);\n                }\n                av_dict_set(&streamOpts, \"scan_all_pmts\", \"1\", AV_DICT_DONT_OVERWRITE);\n\n                formatContext = avformat_alloc_context();\n                formatContext->interrupt_callback.opaque = interruptionRequestedFlag;\n                formatContext->interrupt_callback.callback = ThisThreadInterruptionRequested;\n\n                error = avformat_open_input(&formatContext, finalUrl.c_str(), iformat, &streamOpts);\n                if (error == 0)\n                {\n                    break;\n                }\n            }\n            auto formatContextGuard = MakeGuard(&formatContext, avformat_close_input);\n            g_interruptionRequestedFlag = nullptr;\n            *interruptionRequestedFlag = false;\n            if (error == 0)\n            {\n                CHANNEL_LOG(ffmpeg_opening) << \"Opening video/audio file...\";\n\n                // Retrieve stream information\n                if (avformat_find_stream_info(formatContext, nullptr) < 0)\n                {\n                    CHANNEL_LOG(ffmpeg_opening) << \"Couldn't find stream information\";\n                    return false;\n                }\n\n                m_formatContexts.push_back(formatContext);\n                formatContextGuard.release();\n\n                break;\n            }\n            if (!isHttps || !useHHO || g_lastLocationHttpHeader.empty() || --redirectsLeft < 0)\n            {\n                char err_buf[AV_ERROR_MAX_STRING_SIZE + 2] = \": \";\n                BOOST_LOG_TRIVIAL(error) << \"Couldn't open video/audio file error \" << error \n                    << (av_strerror(error, err_buf + 2, sizeof(err_buf) - 2) == 0 ? err_buf : \"\")\n                    << \" url = \" << url;\n                return false;\n            }\n\n            url = g_lastLocationHttpHeader;\n            CHANNEL_LOG(ffmpeg_opening) << \"Redirecting to URL: \" << url;\n        }\n    }\n\n    return doOpen(urls);\n}\n\nbool FFmpegDecoder::openStream(std::unique_ptr<std::streambuf> stream)\n{\n    close();\n\n    auto ioCtx = std::make_unique<DecoderIOContext>(std::move(stream));\n\n    auto formatContext = avformat_alloc_context();\n\n    auto formatContextGuard = MakeGuard(&formatContext, avformat_close_input);\n\n    ioCtx->initAVFormatContext(formatContext);\n\n    formatContext->interrupt_callback.callback = ThisThreadInterruptionRequested;\n\n    AVDictionary *streamOpts = nullptr;\n    auto avOptionsGuard = MakeGuard(&streamOpts, av_dict_free);\n\n    const int error = avformat_open_input(&formatContext, nullptr, nullptr, &streamOpts);\n    if (error != 0)\n    {\n        char err_buf[AV_ERROR_MAX_STRING_SIZE + 2] = \": \";\n        BOOST_LOG_TRIVIAL(error) << \"Couldn't open video/audio stream error \" << error\n            << (av_strerror(error, err_buf + 2, sizeof(err_buf) - 2) == 0 ? err_buf : \"\");\n        return false;\n    }\n    CHANNEL_LOG(ffmpeg_opening) << \"Opening video/audio file...\";\n\n    // Retrieve stream information\n    if (avformat_find_stream_info(formatContext, nullptr) < 0)\n    {\n        CHANNEL_LOG(ffmpeg_opening) << \"Couldn't find stream information\";\n        return false;\n    }\n\n    m_formatContexts.push_back(formatContext);\n    formatContextGuard.release();\n    m_ioCtx = std::move(ioCtx);\n\n    return doOpen();\n}\n\nbool FFmpegDecoder::doOpen(const std::initializer_list<std::string>& urls)\n{\n    m_referenceTime = boost::chrono::high_resolution_clock::now().time_since_epoch();\n\n    // Find the first video stream\n    m_videoContextIndex = -1;\n    m_videoStreamNumber = -1;\n    m_audioContextIndex = -1;\n    m_audioStreamNumber = -1;\n    for (int contextIdx = m_formatContexts.size(); --contextIdx >= 0;)\n    {\n        const auto formatContext = m_formatContexts[contextIdx];\n        for (int i = formatContext->nb_streams; --i >= 0;)\n        {\n            auto stream = formatContext->streams[i];\n            switch (stream->codecpar->codec_type)\n            {\n            case AVMEDIA_TYPE_VIDEO:\n                stream->discard = AVDISCARD_ALL;\n                m_videoContextIndex = contextIdx;\n                m_videoStreamNumber = i;\n                break;\n            case AVMEDIA_TYPE_AUDIO:\n                if (m_audioContextIndex == -1 || m_audioContextIndex == contextIdx)\n                {\n                    m_audioIndices.push_back(i);\n                    m_audioStream = stream;\n                    m_audioContextIndex = contextIdx;\n                    m_audioStreamNumber = i;\n                }\n                break;\n            }\n        }\n    }\n\n    const auto firstUnused = (std::max)(m_videoContextIndex, m_audioContextIndex) + 1;\n    if (firstUnused == 0)\n        return false;\n\n    for (int contextIdx = m_formatContexts.size(); --contextIdx >= firstUnused;)\n    {\n        avformat_close_input(&m_formatContexts[contextIdx]);\n    }\n\n    m_formatContexts.resize(firstUnused);\n\n    if (m_videoStreamNumber != -1)\n    {\n        m_videoStreamNumber = av_find_best_stream(\n            m_formatContexts[m_videoContextIndex], AVMEDIA_TYPE_VIDEO, \n            m_videoStreamNumber, \n            -1, nullptr, 0);\n\n        m_videoStream = m_formatContexts[m_videoContextIndex]->streams[m_videoStreamNumber];\n        m_videoStream->discard = AVDISCARD_DEFAULT;\n    }\n\n    std::reverse(m_audioIndices.begin(), m_audioIndices.end());\n\n    LoadSubtitleItems(urls);\n\n    AVStream* timeStream = nullptr;\n\n    if (m_videoStreamNumber == -1)\n    {\n        CHANNEL_LOG(ffmpeg_opening) << \"Can't find video stream\";\n    }\n    else\n    {\n        timeStream = m_videoStream;\n    }\n\n    int contextIdx = m_videoContextIndex;\n\n    if (m_audioStreamNumber == -1)\n    {\n        CHANNEL_LOG(ffmpeg_opening) << \"No audio stream\";\n        if (m_videoStreamNumber == -1)\n        {\n            return false; // no multimedia\n        }\n    }\n    else if (!basedOnVideoStream())\n    {\n        // Changing video -> audio duration\n        timeStream = m_audioStream;\n        contextIdx = m_audioContextIndex;\n    }\n\n    m_startTime = (timeStream->start_time > 0)\n        ? timeStream->start_time\n        : ((m_formatContexts[contextIdx]->start_time == AV_NOPTS_VALUE)? 0 \n            : int64_t((m_formatContexts[contextIdx]->start_time / av_q2d(timeStream->time_base)) / AV_TIME_BASE));\n    m_duration = (timeStream->duration > 0)\n        ? timeStream->duration\n        : ((m_formatContexts[contextIdx]->duration == AV_NOPTS_VALUE)? 0\n            : int64_t((m_formatContexts[contextIdx]->duration / av_q2d(timeStream->time_base)) / AV_TIME_BASE));\n\n    if (!resetVideoProcessing())\n    {\n        return false;\n    }\n\n    if (!setupAudioProcessing())\n    {\n        return false;\n    }\n\n    return true;\n}\n\nvoid FFmpegDecoder::LoadSubtitleItems(const std::initializer_list<std::string>& urls)\n{\n    int lastSubtitleNr = 0;\n    for (int contextIdx = 0; contextIdx < m_formatContexts.size(); ++contextIdx)\n    {\n        const auto formatContext = m_formatContexts[contextIdx];\n        for (int i = 0; i < formatContext->nb_streams; ++i)\n        {\n            if (formatContext->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)\n            {\n                std::string description;\n                if (auto title = av_dict_get(formatContext->streams[i]->metadata, \"title\", nullptr, 0))\n                {\n                    description = title->value;\n                }\n                else\n                {\n                    description = \"Track \" + std::to_string(++lastSubtitleNr);\n                    if (auto lang = av_dict_get(formatContext->streams[i]->metadata, \"language\", nullptr, 0))\n                    {\n                        description += \" (\";\n                        description += lang->value;\n                        description += ')';\n                    }\n                }\n                boost::lock_guard<boost::mutex> locker(m_addIntervalMutex);\n                m_subtitleItems.push_back({ contextIdx, i, std::move(description),\n                    (urls.size() == 0) ? std::string() : *(urls.begin() + contextIdx) });\n            }\n        }\n    }\n}\n\nbool FFmpegDecoder::resetVideoProcessing()\n{\n    FreeVideoCodecContext(m_videoCodecContext);\n\n    // Find the decoder for the video stream\n    if (m_videoStreamNumber >= 0)\n    {\n        CHANNEL_LOG(ffmpeg_opening) << \"Video stream number: \" << m_videoStreamNumber;\n        m_videoCodecContext = avcodec_alloc_context3(nullptr);\n        if (m_videoCodecContext == nullptr) {\n            return false;\n        }\n\n        auto videoCodecContextGuard = MakeGuard(&m_videoCodecContext, avcodec_free_context);\n\n        if (avcodec_parameters_to_context(m_videoCodecContext, m_videoStream->codecpar) < 0) {\n            return false;\n        }\n\n        m_videoCodecContext->pkt_timebase = m_videoStream->time_base;\n\n        m_videoCodec = avcodec_find_decoder(m_videoCodecContext->codec_id);\n        if (m_videoCodec == nullptr)\n        {\n            assert(false && \"No such codec found\");\n            return false;  // Codec not found\n        }\n\n        m_videoCodecContext->codec_id = m_videoCodec->id;\n\n#ifdef USE_HWACCEL\n        if (m_hwAccelerated)\n        {\n            m_videoCodecContext->coded_width = m_videoCodecContext->width;\n            m_videoCodecContext->coded_height = m_videoCodecContext->height;\n\n            m_videoCodecContext->thread_count = 1;  // Multithreading is apparently not compatible with hardware decoding\n\n            if (dxva2_init(m_videoCodecContext) >= 0)\n            {\n#if LIBAVCODEC_VERSION_MAJOR < 59\n                m_videoCodecContext->thread_safe_callbacks = 1;\n#endif\n            }\n            else\n            {\n                m_videoCodecContext->thread_count = 2;\n                m_videoCodecContext->flags2 |= AV_CODEC_FLAG2_FAST;\n            }\n        }\n        else\n#endif\n        {\n            m_videoCodecContext->thread_count = 2;\n            m_videoCodecContext->flags2 |= AV_CODEC_FLAG2_FAST;\n        }\n\n\n    // Open codec\n        if (avcodec_open2(m_videoCodecContext, m_videoCodec, nullptr) < 0)\n        {\n            assert(false && \"Error on codec opening\");\n            return false;  // Could not open codec\n        }\n\n        // this may be a valid case\n        //if (m_videoCodecContext->width <= 0 || m_videoCodecContext->height <= 0)\n        //{\n        //    assert(false && \"This file lacks resolution\");\n        //    return false;  // Could not open codec\n        //}\n\n        videoCodecContextGuard.release();\n    }\n\n    return true;\n}\n\nbool FFmpegDecoder::setupAudioProcessing()\n{\n    m_audioCurrentPref = m_audioSettings;\n\n    const auto audioStreamNumber = m_audioStreamNumber.load();\n    if (audioStreamNumber >= 0)\n    {\n        CHANNEL_LOG(ffmpeg_opening) << \"Audio stream number: \" << audioStreamNumber;\n        m_audioCodecContext = avcodec_alloc_context3(nullptr);\n        if (m_audioCodecContext == nullptr) {\n            return false;\n        }\n\n        auto audioCodecContextGuard = MakeGuard(&m_audioCodecContext, avcodec_free_context);\n\n        if (!setupAudioCodec()) {\n            return false;\n        }\n\n        if (!initAudioOutput()) {\n            return false;\n        }\n\n        audioCodecContextGuard.release();\n    }\n\n    return true;\n}\n\nbool FFmpegDecoder::setupAudioCodec()\n{\n    if (avcodec_parameters_to_context(m_audioCodecContext, m_audioStream->codecpar) < 0) {\n        return false;\n    }\n\n    // Find audio codec\n    m_audioCodec = avcodec_find_decoder(m_audioCodecContext->codec_id);\n    if (m_audioCodec == nullptr)\n    {\n        assert(false && \"No such codec found\");\n        return false;  // Codec not found\n    }\n\n    // Open audio codec\n    if (avcodec_open2(m_audioCodecContext, m_audioCodec, nullptr) < 0)\n    {\n        assert(false && \"Error on codec opening\");\n        return false;  // Could not open codec\n    }\n\n    return true;\n}\n\nbool FFmpegDecoder::initAudioOutput()\n{\n    return m_audioPlayer->Open(av_get_bytes_per_sample(m_audioSettings.format),\n        m_audioSettings.num_channels(), &m_audioSettings.frequency);\n}\n\nvoid FFmpegDecoder::play(bool isPaused)\n{\n    CHANNEL_LOG(ffmpeg_opening) << \"Starting playing\";\n\n    m_isPaused = isPaused;\n\n    if (isPaused)\n    {\n        boost::lock_guard<boost::mutex> locker(m_isPausedMutex);\n        m_pauseTimer = GetHiResTime();\n    }\n\n    if (m_mainParseThreads.empty())\n    {\n        m_isPlaying = true;\n        for (int i = 0; i < m_formatContexts.size(); ++i)\n        {\n            m_mainParseThreads.push_back(std::make_unique<boost::thread>(&FFmpegDecoder::parseRunnable, this, i));\n        }\n        m_mainDisplayThread = std::make_unique<boost::thread>(&FFmpegDecoder::displayRunnable, this);\n        CHANNEL_LOG(ffmpeg_opening) << \"Playing\";\n    }\n}\n\nvoid FFmpegDecoder::AppendFrameClock(double frame_clock)\n{\n    if (!basedOnVideoStream() && m_decoderListener != nullptr && m_seekDuration == AV_NOPTS_VALUE)\n    {\n        m_decoderListener->changedFramePosition(\n            m_startTime,\n            int64_t((m_audioPTS + frame_clock) / av_q2d(m_audioStream->time_base)), \n            m_duration + m_startTime);\n    }\n\n    const auto speed = getSpeedRational();\n    InterLockedAdd(m_audioPTS, frame_clock * speed.numerator / speed.denominator);\n}\n\nvoid FFmpegDecoder::setVolume(double volume)\n{\n    if (volume < 0 || volume > 1.)\n    {\n        return;\n    }\n\n    CHANNEL_LOG(ffmpeg_volume) << \"Volume: \" << volume;\n\n    m_audioPlayer->SetVolume(volume);\n\n    if (m_decoderListener != nullptr) {\n        m_decoderListener->volumeChanged(volume);\n    }\n}\n\ndouble FFmpegDecoder::volume() const { return m_audioPlayer->GetVolume(); }\n\nvoid FFmpegDecoder::SetFrameFormat(FrameFormat format, bool allowDirect3dData)\n{ \n    static_assert(PIX_FMT_YUV420P == AV_PIX_FMT_YUV420P, \"FrameFormat and AVPixelFormat values must coincide.\");\n    static_assert(PIX_FMT_YUYV422 == AV_PIX_FMT_YUYV422, \"FrameFormat and AVPixelFormat values must coincide.\");\n    static_assert(PIX_FMT_RGB24 == AV_PIX_FMT_RGB24,     \"FrameFormat and AVPixelFormat values must coincide.\");\n    static_assert(PIX_FMT_BGR24 == AV_PIX_FMT_BGR24,     \"FrameFormat and AVPixelFormat values must coincide.\");\n\n    m_pixelFormat = static_cast<AVPixelFormat>(format);\n    m_allowDirect3dData = allowDirect3dData;\n}\n\nvoid FFmpegDecoder::doOnFinishedDisplayingFrame(unsigned int generation, FinishedDisplayingMode mode)\n{\n    {\n        boost::lock_guard<boost::mutex> locker(m_videoFramesMutex);\n        if (!m_frameDisplayingRequested || generation != m_generation)\n        {\n            return;\n        }\n\n        if (mode != FINALIZE_DISPLAY && m_videoFramesQueue.canPop())\n        {\n            VideoFrame &current_frame = m_videoFramesQueue.front();\n            if (current_frame.m_image->format == AV_PIX_FMT_DXVA2_VLD)\n            {\n                av_frame_unref(current_frame.m_image.get());\n            }\n\n            m_videoFramesQueue.popFront();\n        }\n\n        if (mode != RELEASE_FRAME)\n        {\n            m_frameDisplayingRequested = false;\n        }\n    }\n    m_videoFramesCV.notify_all();\n}\n\nbool FFmpegDecoder::seekDuration(int64_t duration)\n{\n    if (m_isPaused && duration == m_currentTime)\n    {\n        return true; // previous frame special case\n    }\n\n    if (!m_mainParseThreads.empty() && m_seekDuration.exchange(duration) == AV_NOPTS_VALUE)\n    {\n        m_videoPacketsQueue.notify();\n        m_audioPacketsQueue.notify();\n    }\n\n    return true;\n}\n\nvoid FFmpegDecoder::videoReset()\n{\n    m_videoResetting = true;\n    if (!m_mainParseThreads.empty() && m_videoResetDuration.exchange(m_currentTime) == AV_NOPTS_VALUE)\n    {\n        m_videoPacketsQueue.notify();\n        m_audioPacketsQueue.notify();\n    }\n}\n\nvoid FFmpegDecoder::seekWhilePaused()\n{\n    boost::lock_guard<boost::mutex> locker(m_isPausedMutex);\n\n    const bool paused = m_isPaused;\n    if (paused)\n    {\n        if (m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED) {\n            InterLockedAdd(m_videoStartClock, GetHiResTime() - m_pauseTimer);\n        }\n        m_pauseTimer = GetHiResTime();\n    }\n\n    m_isVideoSeekingWhilePaused = paused;\n}\n\nbool FFmpegDecoder::seekByPercent(double percent)\n{\n    return seekDuration(m_startTime + int64_t(m_duration * percent));\n}\n\nbool FFmpegDecoder::getFrameRenderingData(FrameRenderingData *data)\n{\n    if (!m_frameDisplayingRequested || m_mainParseThreads.empty() || m_videoResetting)\n    {\n        return false;\n    }\n\n    VideoFrame &current_frame = m_videoFramesQueue.front();\n    if (current_frame.m_image == nullptr)\n    {\n        return false;\n    }\n#ifdef USE_HWACCEL\n    if (current_frame.m_image->format == AV_PIX_FMT_DXVA2_VLD)\n    {\n        data->d3d9device = get_device(m_videoCodecContext);\n        auto surface = static_cast<IDirect3DSurface9*>(static_cast<void*>(current_frame.m_image->data[3]));\n        if (surface == nullptr)\n        {\n            return false;\n        }\n        data->surface = surface;\n    }\n#endif\n\n    data->image = current_frame.m_image->data;\n    data->pitch = current_frame.m_image->linesize;\n    data->width = current_frame.m_image->width;\n    data->height = current_frame.m_image->height;\n    if (current_frame.m_image->sample_aspect_ratio.num != 0\n        && current_frame.m_image->sample_aspect_ratio.den != 0)\n    {\n        data->aspectNum = current_frame.m_image->sample_aspect_ratio.num;\n        data->aspectDen = current_frame.m_image->sample_aspect_ratio.den;\n    }\n    else if (m_videoStream && m_videoStream->sample_aspect_ratio.num != 0\n        && m_videoStream->sample_aspect_ratio.den != 0)\n    {\n        data->aspectNum = m_videoStream->sample_aspect_ratio.num;\n        data->aspectDen = m_videoStream->sample_aspect_ratio.den;\n    }\n    else\n    {\n        data->aspectNum = 1;\n        data->aspectDen = 1;\n    }\n\n    return true;\n}\n\ndouble FFmpegDecoder::getDurationSecs(int64_t duration) const\n{\n    return av_q2d(basedOnVideoStream()\n                      ? m_videoStream->time_base\n                      : m_audioStream->time_base) *\n           duration;\n}\n\nbool FFmpegDecoder::pauseResume()\n{\n    if (m_mainParseThreads.empty())\n    {\n        return false;\n    }\n\n    if (!m_isPaused)\n    {\n        CHANNEL_LOG(ffmpeg_pause) << \"Pause\";\n        {\n            boost::lock_guard<boost::mutex> locker(m_isPausedMutex);\n            m_isPaused = true;\n            m_pauseTimer = GetHiResTime();\n        }\n        m_videoFramesCV.notify_all();\n        m_videoPacketsQueue.notify();\n        m_audioPacketsQueue.notify();\n\n        return true;\n    }\n\n    CHANNEL_LOG(ffmpeg_pause) << \"Resume\";\n    {\n        boost::lock_guard<boost::mutex> locker(m_isPausedMutex);\n        if (m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED) {\n            InterLockedAdd(m_videoStartClock, GetHiResTime() - m_pauseTimer);\n        }\n        m_isVideoSeekingWhilePaused = false;\n        m_isPaused = false;\n        m_prevTime = AV_NOPTS_VALUE;\n    }\n    m_isPausedCV.notify_all();\n\n    return true;\n}\n\nbool FFmpegDecoder::nextFrame()\n{\n    if (m_mainParseThreads.empty())\n    {\n        return false;\n    }\n\n    if (m_videoPacketsQueue.empty())\n    {\n        return false;\n    }\n\n    if (m_prevTime != AV_NOPTS_VALUE)\n    {\n        return false;\n    }\n\n    CHANNEL_LOG(ffmpeg_pause) << \"Next frame\";\n    {\n        boost::lock_guard<boost::mutex> locker(m_isPausedMutex);\n\n        if (!m_isPaused || m_isVideoSeekingWhilePaused)\n        {\n            return false;\n        }\n \n        const auto currentTime = GetHiResTime();\n        if (m_videoStartClock != VIDEO_START_CLOCK_NOT_INITIALIZED) {\n            InterLockedAdd(m_videoStartClock, currentTime - m_pauseTimer);\n        }\n        m_pauseTimer = currentTime;\n\n        m_isVideoSeekingWhilePaused = true;\n    }\n    m_isPausedCV.notify_all();\n    m_videoPacketsQueue.notify();\n    return true;\n}\n\nbool FFmpegDecoder::prevFrame()\n{\n    if (m_mainParseThreads.empty())\n    {\n        return false;\n    }\n\n    if (!m_videoStream || m_videoStream->r_frame_rate.den <= 0 || m_videoStream->time_base.den <= 0\n        || m_videoStream->r_frame_rate.num <= 0 || m_videoStream->time_base.num <= 0)\n    {\n        return false;\n    }\n\n    if (m_prevTime != AV_NOPTS_VALUE)\n    {\n        return false;\n    }\n\n    CHANNEL_LOG(ffmpeg_pause) << \"Previous frame\";\n    {\n        boost::lock_guard<boost::mutex> locker(m_isPausedMutex);\n\n        if (!m_isPaused || m_isVideoSeekingWhilePaused)\n        {\n            return false;\n        }\n        int64_t expected = AV_NOPTS_VALUE;\n        if (!m_seekDuration.compare_exchange_strong(expected, m_currentTime))\n        {\n            return false;\n        }\n    }\n    m_videoPacketsQueue.notify();\n    m_audioPacketsQueue.notify();\n    return true;\n}\n\n\nint FFmpegDecoder::getNumAudioTracks() const\n{\n    return m_audioIndices.size();\n}\n\nint FFmpegDecoder::getAudioTrack() const\n{\n    const auto audioStreamNumber = m_audioStreamNumber.load();\n    return (audioStreamNumber < 0)\n        ? -1\n        : std::find(m_audioIndices.begin(), m_audioIndices.end(), audioStreamNumber) - m_audioIndices.begin();\n}\n\nvoid FFmpegDecoder::setAudioTrack(int idx)\n{\n    if (idx >= 0 && idx < m_audioIndices.size()) {\n        m_audioStreamNumber = m_audioIndices[idx];\n    }\n}\n\nRationalNumber FFmpegDecoder::getSpeedRational() const\n{\n    return m_speedRational;\n}\n\nvoid FFmpegDecoder::setSpeedRational(const RationalNumber& speed)\n{\n    boost::lock_guard<boost::mutex> locker(m_isPausedMutex);\n\n    const auto time = GetHiResTime();\n    m_speedRational = speed;\n\n    m_referenceTime = (boost::chrono::high_resolution_clock::now()\n            - boost::chrono::microseconds(int64_t(time * speed.denominator / speed.numerator * 1000000.)))\n        .time_since_epoch();\n}\n\nstd::vector<std::string> FFmpegDecoder::getProperties() const\n{\n    std::vector<std::string> result;\n\n    for (auto formatContext : m_formatContexts)\n    {\n        if (formatContext && formatContext->iformat && formatContext->iformat->long_name)\n            result.emplace_back(formatContext->iformat->long_name);\n    }\n\n    if (m_videoCodec && m_videoCodec->long_name)\n        result.emplace_back(m_videoCodec->long_name);\n\n    if (m_videoStream && m_videoCodecContext)\n    {\n        const auto eps_zero = 0.000025;\n\n        double fps = 0;\n        if (m_videoStream->r_frame_rate.den)\n            fps = av_q2d(m_videoStream->r_frame_rate);\n\n        if (fps < eps_zero && m_videoStream->avg_frame_rate.den)\n            fps = av_q2d(m_videoStream->avg_frame_rate);\n\n        if (fps < eps_zero && m_videoStream->time_base.num && m_videoStream->time_base.den)\n            fps = 1.0 / av_q2d(m_videoStream->time_base);\n\n        int bpp = 0;\n        int depth = 0;\n        if (auto av_pix_fmt_desc = av_pix_fmt_desc_get(\n            (m_videoCodecContext->sw_pix_fmt == AV_PIX_FMT_NONE)\n                ? m_videoCodecContext->pix_fmt : m_videoCodecContext->sw_pix_fmt))\n        {\n            bpp = av_get_bits_per_pixel(av_pix_fmt_desc);\n            for (int i = 0; i < av_pix_fmt_desc->nb_components; ++i)\n                if (av_pix_fmt_desc->comp[i].depth > depth)\n                    depth = av_pix_fmt_desc->comp[i].depth;\n        }\n\n        char buffer[1000];\n        snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]),\n            \"%d / %d @ %.2f FPS %d BPP %d bits\", \n            m_videoCodecContext->width, m_videoCodecContext->height, fps, bpp, depth);\n        result.emplace_back(buffer);\n    }\n\n    if (m_audioCodec && m_audioCodec->long_name)\n        result.emplace_back(m_audioCodec->long_name);\n\n    return result;\n}\n\nstd::pair<int, int> FFmpegDecoder::getVideoSize() const\n{\n    return m_videoCodecContext\n        ? std::pair<int, int>(m_videoCodecContext->width, m_videoCodecContext->height)\n        : std::pair<int, int>();\n}\n\nstd::pair<bool, bool> FFmpegDecoder::isVideoAudioCompatible() const\n{\n    auto videoLam = [this]\n    {\n        if (!m_videoCodec || !m_videoCodecContext)\n        {\n            return false;\n        }\n\n        if (m_videoCodecContext->color_trc == AVCOL_TRC_BT709)\n        {\n            return false;\n        }\n\n        if (m_videoCodec->id != AV_CODEC_ID_H264 && m_videoCodec->id != AV_CODEC_ID_MPEG2VIDEO &&\n            m_videoCodec->id != AV_CODEC_ID_MPEG4)\n        {\n            return false;\n        }\n\n        if (auto d = av_pix_fmt_desc_get((m_videoCodecContext->sw_pix_fmt == AV_PIX_FMT_NONE)\n                                             ? m_videoCodecContext->pix_fmt\n                                             : m_videoCodecContext->sw_pix_fmt))\n        {\n            for (int i = 0; i < d->nb_components; ++i)\n                if (d->comp[i].depth > 8)\n                    return false;\n        }\n        else\n        {\n            return false;\n        }\n\n        return true;\n    };\n\n    return {videoLam(), m_audioCodec && m_audioCodecContext &&\n                            (m_audioCodec->id == AV_CODEC_ID_MP3 ||\n                             m_audioCodec->id == AV_CODEC_ID_AAC &&\n                                 (m_audioCodecContext->profile == AV_PROFILE_AAC_LOW ||\n                                  m_audioCodecContext->profile == AV_PROFILE_AAC_HE)) &&\n                            m_audioCurrentPref.num_channels() == 2};\n}\n\n\nvoid FFmpegDecoder::handleDirect3dData(AVFrame* videoFrame, bool forceConversion)\n{\n#ifdef USE_HWACCEL\n    if ((forceConversion || !m_allowDirect3dData) && videoFrame->format == AV_PIX_FMT_DXVA2_VLD)\n    {\n        dxva2_retrieve_data(m_videoCodecContext, videoFrame);\n        assert(videoFrame->format != AV_PIX_FMT_DXVA2_VLD);\n    }\n#endif\n}\n\ndouble FFmpegDecoder::GetHiResTime() const\n{\n    const auto speed = getSpeedRational();\n    return boost::chrono::duration_cast<boost::chrono::microseconds>(\n        boost::chrono::high_resolution_clock::now() - boost::chrono::high_resolution_clock::time_point(m_referenceTime)).count()\n            / 1000000. * speed.numerator / speed.denominator;\n}\n\nbool FFmpegDecoder::basedOnVideoStream() const \n{ \n    return m_videoStream != nullptr &&\n           (m_audioStream == nullptr ||\n            (m_videoStream->disposition & AV_DISPOSITION_ATTACHED_PIC) == 0);\n}\n\nbool FFmpegDecoder::getHwAccelerated() const\n{\n    return m_hwAccelerated;\n}\n\nvoid FFmpegDecoder::setHwAccelerated(bool hwAccelerated)\n{\n    m_hwAccelerated = hwAccelerated;\n}\n\nstd::vector<std::string> FFmpegDecoder::listSubtitles() const\n{\n    std::vector<std::string> result;\n    boost::lock_guard<boost::mutex> locker(m_addIntervalMutex);\n    for (const auto& item : m_subtitleItems)\n    {\n        result.push_back(item.description);\n    }\n\n    return result;\n}\n\nbool FFmpegDecoder::getSubtitles(int idx, std::function<bool(double, double, const std::string&)> addIntervalCallback)\n{\n    int streamNumber;\n    std::string url;\n\n    {\n        boost::lock_guard<boost::mutex> locker(m_addIntervalMutex);\n\n        if (idx < 0 || idx >= m_subtitleItems.size())\n            return false;\n\n        m_subtitleIdx = idx;\n        m_addIntervalCallback = addIntervalCallback;\n\n        avcodec_free_context(&m_subtitlesCodecContext);\n\n        const auto& subtitleItem = m_subtitleItems.at(idx);\n        if (subtitleItem.url.empty())\n        {\n            return true;\n        }\n\n        streamNumber = subtitleItem.streamIdx;\n        url = subtitleItem.url;\n    }\n\n\n    auto formatContext = avformat_alloc_context();\n    if (formatContext == nullptr) {\n        return false;\n    }\n\n    auto formatContextGuard = MakeGuard(&formatContext, avformat_close_input);\n\n    int error = avformat_open_input(&formatContext, url.c_str(), nullptr, nullptr);\n    if (error != 0)\n    {\n        return false;\n    }\n\n    auto codecContext = MakeSubtitlesCodecContext(formatContext->streams[streamNumber]->codecpar);\n    if (codecContext == nullptr) {\n        return false;\n    }\n\n    auto codecContextGuard = MakeGuard(&codecContext, avcodec_free_context);\n\n    bool ok = false;\n    AVPacket packet;\n    while (av_read_frame(formatContext, &packet) >= 0)\n    {\n        if (packet.stream_index == streamNumber)\n        {\n            std::string text = GetSubtitle(codecContext, packet);\n            if (!text.empty())\n            {\n                if (!addIntervalCallback(packet.pts / 1000., (packet.pts + packet.duration) / 1000., text))\n                {\n                    av_packet_unref(&packet);\n                    return false;\n                }\n                ok = true;\n            }\n        }\n        av_packet_unref(&packet);\n    }\n\n    return ok;\n}\n\nvoid FFmpegDecoder::setImageConversionFunc(ImageConversionFunc func)\n{\n    m_imageConversionFunc = boost::make_shared<ImageConversionFunc>(std::move(func));\n}\n"
  },
  {
    "path": "video/ffmpegdecoder.h",
    "content": "#pragma once\n\n#include \"decoderinterface.h\"\n#include \"audioplayer.h\"\n\nextern \"C\" {\n#include <libavcodec/avcodec.h>\n#include <libavformat/avformat.h>\n#include <libswscale/swscale.h>\n#include <libswresample/swresample.h>\n//#include <libavdevice/avdevice.h>\n}\n\n#include <string>\n#include <boost/thread/thread.hpp>\n#include <boost/atomic.hpp>\n#include <boost/smart_ptr/atomic_shared_ptr.hpp>\n#include <memory>\n#include <vector>\n\n#include <boost/chrono.hpp>\n#include <boost/log/sources/channel_logger.hpp>\n#include <boost/log/common.hpp>\n\nnamespace channel_logger\n{\n\n// Weird x64 debug build crash fixed\n\n#if defined(_MSC_VER) && _MSC_VER < 1910\n\nclass ChannelLogger : public boost::log::sources::channel_logger_mt<>\n{\n    template<typename... T>\n    auto open_record_unlocked(basic_logger<T...>*)\n    {\n        return basic_logger<T...>::open_record_unlocked();\n    }\npublic:\n    using channel_logger_mt<>::channel_logger_mt;\n    boost::log::record open_record()\n    {\n        // Perform a quick check first\n        if (this->core()->get_logging_enabled())\n        {\n            open_record_lock lock(this->get_threading_model());\n            return open_record_unlocked(this);\n        }\n        return boost::log::record();\n    }\n};\n\n#else\n\nusing ChannelLogger = boost::log::sources::channel_logger_mt<>;\n\n#endif\n\nextern ChannelLogger\n    ffmpeg_closing, \n    ffmpeg_opening, \n    ffmpeg_pause,\n    ffmpeg_seek, \n    ffmpeg_sync,\n    ffmpeg_threads, \n    ffmpeg_volume,\n    ffmpeg_internal;\n\n} // namespace channel_logger\n\n#define CHANNEL_LOG(channel) BOOST_LOG(::channel_logger::channel)\n\n#include \"fqueue.h\"\n#include \"videoframe.h\"\n#include \"vqueue.h\"\n\nstruct RendezVousData\n{\n    boost::mutex mtx;\n    unsigned int generation{};\n    unsigned int count{};\n    boost::condition_variable cond;\n};\n\nclass DecoderIOContext;\n\n\n// Inspired by http://dranger.com/ffmpeg/ffmpeg.html\n\nclass FFmpegDecoder final : public IFrameDecoder, public IAudioPlayerCallback\n{\n   public:\n    FFmpegDecoder(std::unique_ptr<IAudioPlayer> audioPlayer);\n    ~FFmpegDecoder() override;\n\n    FFmpegDecoder(const FFmpegDecoder&) = delete;\n    FFmpegDecoder& operator=(const FFmpegDecoder&) = delete;\n\n    void SetFrameFormat(FrameFormat format, bool allowDirect3dData) override;\n\n    bool openUrls(std::initializer_list<std::string> urls, const std::string& inputFormat = {}, bool useHHO = false) override;\n    bool openStream(std::unique_ptr<std::streambuf> stream) override;\n    bool seekDuration(int64_t duration);\n    bool seekByPercent(double percent) override;\n\n    void videoReset() override;\n\n    double volume() const override;\n\n    bool isPlaying() const override { return m_isPlaying; }\n    bool isPaused() const override { return m_isPaused; }\n\n    void setFrameListener(IFrameListener* listener) override { m_frameListener = listener; }\n\n    void setDecoderListener(FrameDecoderListener* listener) override\n    {\n        m_decoderListener = listener;\n    }\n\n    bool getFrameRenderingData(FrameRenderingData* data) override;\n\n    double getDurationSecs(int64_t duration) const override;\n\n    void doOnFinishedDisplayingFrame(unsigned int generation, FinishedDisplayingMode mode) override;\n\n    void close() override;\n    void play(bool isPaused = false) override;\n    bool pauseResume() override;\n    bool nextFrame() override;\n    bool prevFrame() override;\n    void setVolume(double volume) override;\n\n    int getNumAudioTracks() const override;\n    int getAudioTrack() const override;\n    void setAudioTrack(int idx) override;\n\n    RationalNumber getSpeedRational() const override;\n    void setSpeedRational(const RationalNumber& speed) override;\n\n    bool getHwAccelerated() const override;\n    void setHwAccelerated(bool hwAccelerated) override;\n\n    std::vector<std::string> getProperties() const override;\n\n    std::pair<int, int> getVideoSize() const override;\n\n    std::pair<bool, bool> isVideoAudioCompatible() const override;\n\n    std::vector<std::string> listSubtitles() const override;\n    bool getSubtitles(int idx, std::function<bool(double, double, const std::string&)> addIntervalCallback) override;\n\n    void setImageConversionFunc(ImageConversionFunc func) override;\n\n   private:\n    struct VideoParseContext;\n\n    // Threads\n    void parseRunnable(int idx);\n    void audioParseRunnable();\n    void videoParseRunnable();\n    void displayRunnable();\n\n    bool doOpen(const std::initializer_list<std::string>& urls = {});\n    void LoadSubtitleItems(const std::initializer_list<std::string>& urls);\n    bool dispatchPacket(int idx, AVPacket& packet);\n    void handleSubtitlePacket(int idx, const AVPacket& packet);\n    void flush(int idx);\n    void startAudioThread();\n    void startVideoThread();\n    bool resetDecoding(int64_t seekDuration, bool resetVideo);\n    bool doSeekFrame(int idx, int64_t seekDuration, AVPacket* packet);\n    bool respawn(int64_t seekDuration, bool resetVideo);\n\n    void fixDuration();\n\n    bool handleAudioPacket(\n        const AVPacket& packet,\n        std::vector<uint8_t>& resampleBuffer,\n        bool failed, double& scheduledEndTime);\n    void setupAudioSwrContext(AVFrame* audioFrame);\n    bool handleAudioFrame(\n        double frame_clock, uint8_t* write_data, int64_t write_size, bool failed);\n    bool handleVideoPacket(\n        const AVPacket& packet,\n        VideoParseContext& context);\n    bool handleVideoFrame(\n        AVFramePtr& frame,\n        VideoParseContext& context,\n        int64_t next_timestamp);\n\n    // IAudioPlayerCallback\n    void AppendFrameClock(double frame_clock) override;\n\n    void resetVariables();\n    void closeProcessing();\n\n    bool resetVideoProcessing();\n    bool setupAudioProcessing();\n    bool setupAudioCodec();\n    bool initAudioOutput();\n\n    void seekWhilePaused();\n\n    void handleDirect3dData(AVFrame* videoFrame, bool forceConversion);\n\n    double GetHiResTime() const;\n\n    bool basedOnVideoStream() const;\n\n    // Frame display listener\n    IFrameListener* m_frameListener;\n\n    FrameDecoderListener* m_decoderListener;\n\n    // Indicators\n    bool m_isPlaying;\n\n    std::unique_ptr<boost::thread> m_mainVideoThread;\n    std::unique_ptr<boost::thread> m_mainAudioThread;\n    std::vector<std::unique_ptr<boost::thread>> m_mainParseThreads;\n    std::unique_ptr<boost::thread> m_mainDisplayThread;\n\n    // Synchronization\n    boost::atomic<double> m_audioPTS;\n\n    // Real duration from video stream\n    int64_t m_startTime;\n    boost::atomic_int64_t m_currentTime;\n    int64_t m_duration;\n\n    boost::atomic_int64_t m_prevTime;\n\n    // Basic stuff\n    std::vector<AVFormatContext*> m_formatContexts;\n\n    std::vector<boost::atomic_bool> m_formatContextInterrupts;\n\n    boost::atomic_int64_t m_seekDuration;\n    boost::atomic_int64_t m_videoResetDuration;\n\n    RendezVousData m_seekRendezVous;\n    RendezVousData m_videoResetRendezVous;\n\n    boost::atomic_bool m_videoResetting;\n\n    // Video Stuff\n    enum { VIDEO_START_CLOCK_NOT_INITIALIZED = -1000000000 };\n    boost::atomic<double> m_videoStartClock;\n\n    const AVCodec* m_videoCodec;\n    AVCodecContext* m_videoCodecContext;\n    AVStream* m_videoStream;\n    int m_videoContextIndex;\n    int m_videoStreamNumber;\n\n    // Audio Stuff\n    const AVCodec* m_audioCodec;\n    AVCodecContext* m_audioCodecContext;\n    AVStream* m_audioStream;\n    int m_audioContextIndex;\n    boost::atomic<int> m_audioStreamNumber;\n    SwrContext* m_audioSwrContext;\n\n    struct AudioParams\n    {\n        int frequency;\n#if LIBAVUTIL_VERSION_MAJOR < 57\n        int channels;\n        int64_t channel_layout;\n        auto num_channels() const { return channels; }\n#else\n        AVChannelLayout channel_layout;\n        auto num_channels() const { return channel_layout.nb_channels; }\n#endif\n        AVSampleFormat format;\n\n        AudioParams() = default;\n        AudioParams(int freq, int chans, AVSampleFormat fmt);\n        ~AudioParams();\n        AudioParams& operator=(const AudioParams& other);\n    };\n    AudioParams m_audioSettings;\n    AudioParams m_audioCurrentPref;\n\n    // Stuff for converting image\n    SwsContext* m_imageCovertContext;\n    AVPixelFormat m_pixelFormat;\n    bool m_allowDirect3dData;\n\n    // Video and audio queues\n    enum\n    {\n        MAX_VIDEO_QUEUE_SIZE = 100 * 1024 * 1024,\n        MAX_AUDIO_QUEUE_SIZE = 15 * 1024 * 1024,\n        MAX_VIDEO_FRAMES = 500,\n        MAX_AUDIO_FRAMES = 500,\n    };\n    FQueue<MAX_VIDEO_QUEUE_SIZE, MAX_VIDEO_FRAMES> m_videoPacketsQueue;\n    FQueue<MAX_AUDIO_QUEUE_SIZE, MAX_AUDIO_FRAMES> m_audioPacketsQueue;\n\n    VQueue m_videoFramesQueue;\n\n    bool m_frameDisplayingRequested;\n\n    unsigned int m_generation = 0;\n\n    boost::mutex m_videoFramesMutex;\n    boost::condition_variable m_videoFramesCV;\n\n    boost::atomic_bool m_isPaused;\n    boost::mutex m_isPausedMutex;\n    boost::condition_variable m_isPausedCV;\n    double m_pauseTimer;\n\n    boost::atomic_bool m_isVideoSeekingWhilePaused;\n\n    // Audio\n    std::unique_ptr<IAudioPlayer> m_audioPlayer;\n    bool m_audioPaused;\n\n    std::vector<int> m_audioIndices;\n\n    std::unique_ptr<DecoderIOContext> m_ioCtx;\n\n    boost::atomic<boost::chrono::high_resolution_clock::duration> m_referenceTime;\n\n    boost::atomic<RationalNumber> m_speedRational; // Numerator, Denominator\n\n    bool m_hwAccelerated;\n\n    struct SubtitleItem {\n        int contextIdx;\n        int streamIdx;\n        std::string description;\n        std::string url;\n    };\n\n    std::vector<SubtitleItem> m_subtitleItems;\n\n    mutable boost::mutex m_addIntervalMutex;\n\n    int m_subtitleIdx;\n    std::function<bool(double, double, const std::string&)> m_addIntervalCallback;\n\n    AVCodecContext* m_subtitlesCodecContext;\n\n    boost::atomic_shared_ptr<ImageConversionFunc> m_imageConversionFunc;\n};\n"
  },
  {
    "path": "video/fqueue.h",
    "content": "#pragma once\n\n#include <boost/thread/thread.hpp>\n#include <deque>\n#include <map>\n#include <type_traits>\n\ntemplate<size_t MAX_QUEUE_SIZE, size_t MAX_FRAMES>\nclass FQueue\n{\npublic:\n    FQueue()  {}\n    FQueue(const FQueue&) = delete;\n    FQueue& operator=(const FQueue&) = delete;\n\n    template<typename T>\n    bool push(const AVPacket& packet, T abortFunc)\n    {\n        const auto pos = packet.pos;\n        const auto dts = packet.dts;\n        auto& prev = m_positions[packet.stream_index];\n        if ((dts != AV_NOPTS_VALUE) ? dts < prev.m_dts\n            : (pos != -1 && pos < prev.m_pos))\n        {\n            return false;\n        }\n\n        bool wasEmpty;\n        {\n            boost::unique_lock<boost::mutex> locker(m_mutex);\n            while (isPacketsQueueFull())\n            {\n                if (abortFunc())\n                {\n                    return false;\n                }\n                m_condVar.wait(locker);\n            }\n            wasEmpty = m_queue.empty();\n            enqueue(packet);\n            if (pos != -1)\n                prev.m_pos = pos;\n            if (dts != AV_NOPTS_VALUE)\n                prev.m_dts = dts;\n        }\n        if (wasEmpty)\n        {\n            m_condVar.notify_all();\n        }\n\n        return true;\n    }\n\n    template<typename T = std::false_type>\n    bool pop(AVPacket& packet, T abortFunc = T())\n    {\n        bool wasFull;\n        {\n            boost::unique_lock<boost::mutex> locker(m_mutex);\n\n            while (m_queue.empty())\n            {\n                if (abortFunc())\n                {\n                    return false;\n                }\n                m_condVar.wait(locker);\n            }\n\n            wasFull = isPacketsQueueFull();\n            packet = dequeue();\n        }\n        if (wasFull)\n        {\n            m_condVar.notify_all();\n        }\n\n        return true;\n    }\n\n    void clear()\n    {\n        for (AVPacket& packet : m_queue)\n        {\n            av_packet_unref(&packet);\n        }\n        m_packetsSize = 0;\n        m_positions.clear();\n        std::deque<AVPacket>().swap(m_queue);\n    }\n\n    bool empty()\n    {\n        boost::lock_guard<boost::mutex> locker(m_mutex);\n        return m_queue.empty();\n    }\n\n    void notify()\n    {\n        m_condVar.notify_all();\n    }\n\nprivate:\n    AVPacket dequeue()\n    {\n        assert(!m_queue.empty());\n        AVPacket packet = m_queue.front();\n        m_queue.pop_front();\n        m_packetsSize -= packet.size;\n        assert(m_packetsSize >= 0);\n        return packet;\n    }\n\n    void enqueue(const AVPacket& packet)\n    {\n        m_packetsSize += packet.size;\n        assert(m_packetsSize >= 0);\n        m_queue.push_back(packet);\n    }\n\n    bool isPacketsQueueFull() const\n    {\n        return m_packetsSize > MAX_QUEUE_SIZE ||\n            m_queue.size() > MAX_FRAMES;\n    }\n\nprivate:\n    struct PositionData\n    {\n        int64_t\tm_pos = -1;\n        int64_t m_dts = AV_NOPTS_VALUE;\n    };\n\n    int64_t\tm_packetsSize = 0;\n    std::deque<AVPacket> m_queue;\n\n    boost::mutex m_mutex;\n    boost::condition_variable m_condVar;\n\n    std::map<int, PositionData> m_positions;\n};\n"
  },
  {
    "path": "video/interlockedadd.h",
    "content": "#pragma once\n\n#include <boost/atomic.hpp>\n\ninline void InterLockedAdd(boost::atomic<double>& clock, double correction)\n{\n    for (double v = clock; !clock.compare_exchange_weak(v, v + correction);)\n    {\n    }\n}\n\n"
  },
  {
    "path": "video/makeguard.h",
    "content": "#pragma once\n\n#include <memory>\n#include <utility>\n\ntemplate<typename T, typename D>\ninline auto MakeGuard(T* t, D d)\n{\n    return std::unique_ptr<T, D>(t, std::move(d));\n}\n"
  },
  {
    "path": "video/ordered_scoped_token.h",
    "content": "// ordered_scoped_token.h\n#pragma once\n\n#include <atomic>\n#include <condition_variable>\n#include <cstdint>\n#include <memory>\n#include <mutex>\n#include <stdexcept>\n#include <unordered_set>\n\nclass OrderedScopedTokenGenerator {\npublic:\n    OrderedScopedTokenGenerator() : ctrl_(std::make_shared<Control>()) {}\n\n    struct LockScope;\n\nprivate:\n    struct Control {\n        std::mutex mtx;\n        std::condition_variable cv;\n        uint64_t next_index{ 0 };   // next index allowed to enter critical section\n        uint64_t alloc_index{ 0 };  // next index to assign\n        // indices that have been consumed (either released or discarded) but are > next_index\n        std::unordered_set<uint64_t> consumed;\n    };\n\n    std::shared_ptr<Control> ctrl_;\n\n    // helper: mark index consumed and advance next_index while possible\n    static void consume_and_advance(const std::shared_ptr<Control>& ctrl, uint64_t index) {\n        std::lock_guard<std::mutex> lk(ctrl->mtx);\n        if (index < ctrl->next_index) {\n            // already passed\n            return;\n        }\n        if (index == ctrl->next_index) {\n            ++ctrl->next_index;\n            // advance while contiguous indices are present in consumed set\n            while (true) {\n                auto it = ctrl->consumed.find(ctrl->next_index);\n                if (it == ctrl->consumed.end()) break;\n                ctrl->consumed.erase(it);\n                ++ctrl->next_index;\n            }\n        }\n        else {\n            // index > next_index: remember it for later coalescing\n            ctrl->consumed.insert(index);\n        }\n        ctrl->cv.notify_all();\n    }\n\npublic:\n    // Movable-only token representing a one-time ordered gate\n    struct Token {\n        Token() = default;\n\n        // non-copyable\n        Token(const Token&) = delete;\n        Token& operator=(const Token&) = delete;\n\n        // movable\n        Token(Token&& other) noexcept = default;\n        Token& operator=(Token&& other) noexcept = default;\n\n        ~Token() {\n            // If token was never claimed (locked or consumed), consume it now so it doesn't block later tokens.\n            // This destructor does NOT block; it marks the index consumed immediately so later tokens can proceed.\n            if (!state_) return;\n            bool expected = false;\n            if (!state_->claimed.compare_exchange_strong(expected, true)) {\n                // already claimed/locked; nothing to do\n                return;\n            }\n            // mark consumed and advance generator (non-blocking)\n            consume_and_advance(state_->ctrl, state_->index);\n        }\n\n        // Acquire the token and enter the critical section.\n        // Returns a movable LockScope that holds the critical section until destroyed.\n        // Throws std::runtime_error if token is invalid or already claimed.\n        LockScope lock() {\n            if (!state_) throw std::runtime_error(\"Invalid token\");\n            bool expected = false;\n            if (!state_->claimed.compare_exchange_strong(expected, true)) {\n                throw std::runtime_error(\"Token already claimed\");\n            }\n\n            std::unique_lock<std::mutex> lk(state_->ctrl->mtx);\n            state_->ctrl->cv.wait(lk, [&] { return state_->ctrl->next_index == state_->index; });\n            // Do NOT advance next_index here; LockScope destructor will advance when scope ends.\n            return LockScope(state_);\n        }\n\n        // Try to acquire immediately. If successful returns LockScope; otherwise returns empty optional.\n        // If token already claimed, returns empty.\n        LockScope try_lock() {\n            if (!state_) return {};\n            bool expected = false;\n            if (!state_->claimed.compare_exchange_strong(expected, true)) {\n                return {}; // already claimed\n            }\n            // check if it's our turn now\n            {\n                std::lock_guard<std::mutex> lk(state_->ctrl->mtx);\n                if (state_->ctrl->next_index != state_->index) {\n                    // Not our turn; we keep claimed=true to respect one-time semantics,\n                    // but try_lock fails to enter the critical section immediately.\n                    return {};\n                }\n            }\n            // It's our turn; return LockScope (do not advance here)\n            return LockScope(state_);\n        }\n\n        // Query whether token has been claimed (locked or consumed)\n        bool is_claimed() const {\n            return state_ && state_->claimed.load();\n        }\n\n        explicit operator bool() const noexcept { return static_cast<bool>(state_); }\n\n    private:\n        friend class OrderedScopedTokenGenerator;\n        struct State {\n            std::shared_ptr<Control> ctrl;\n            uint64_t index;\n            std::atomic<bool> claimed{ false }; // ensures token is used only once\n        };\n\n        explicit Token(std::shared_ptr<State> s) : state_(std::move(s)) {}\n        std::shared_ptr<State> state_;\n    };\n\n    // RAII scope returned by Token::lock(); movable-only.\n    struct LockScope {\n        LockScope() = default;\n\n        // non-copyable\n        LockScope(const LockScope&) = delete;\n        LockScope& operator=(const LockScope&) = delete;\n\n        // movable\n        LockScope(LockScope&& other) noexcept\n            : state_(std::exchange(other.state_, {})), owns_(other.owns_) {\n            other.owns_ = false;\n        }\n        LockScope& operator=(LockScope&& other) noexcept {\n            if (this != &other) {\n                release_if_needed();\n                state_ = std::exchange(other.state_, {});\n                owns_ = other.owns_;\n                other.owns_ = false;\n            }\n            return *this;\n        }\n\n        ~LockScope() {\n            release_if_needed();\n        }\n\n        // explicit release before destruction (optional)\n        void release() {\n            release_if_needed();\n        }\n\n        bool valid() const noexcept { return state_ && owns_; }\n\n    private:\n        friend struct Token;\n        explicit LockScope(std::shared_ptr<Token::State> s) : state_(std::move(s)), owns_(true) {}\n\n        void release_if_needed() {\n            if (!state_ || !owns_) return;\n            // mark consumed and advance generator\n            consume_and_advance(state_->ctrl, state_->index);\n            owns_ = false;\n        }\n\n        std::shared_ptr<Token::State> state_;\n        bool owns_{ false };\n    };\n\n    // generate a new movable-only token\n    Token generate() {\n        uint64_t idx;\n        {\n            // allocate index under mutex to avoid ABA with consumed set (not strictly necessary but simpler)\n            std::lock_guard<std::mutex> lk(ctrl_->mtx);\n            idx = ctrl_->alloc_index++;\n        }\n        auto s = std::make_shared<Token::State>();\n        s->ctrl = ctrl_;\n        s->index = idx;\n        s->claimed.store(false);\n        return Token(s);\n    }\n};\n"
  },
  {
    "path": "video/parserunnable.cpp",
    "content": "#include \"ffmpegdecoder.h\"\n#include \"makeguard.h\"\n#include \"subtitles.h\"\n\n#include <algorithm>\n#include <chrono>\n#include <memory>\n\n#ifdef _WIN32\n#include <winerror.h>\n#else\n#include <errno.h>\n#endif\n\nconst int AVERROR_ECONNRESET = \n#ifdef _WIN32\n    AVERROR(WSAECONNRESET);\n#else\n    AVERROR(ECONNRESET);\n#endif\n\nnamespace {\n\nbool isSeekable(AVFormatContext* formatContext)\n{\n#ifdef AVFMTCTX_UNSEEKABLE\n    return ((formatContext->ctx_flags & AVFMTCTX_UNSEEKABLE) == 0);\n#else\n    return (formatContext->pb == nullptr || (formatContext->pb->seekable & AVIO_SEEKABLE_NORMAL) != 0) &&\n        (formatContext->iformat->name == nullptr || strcmp(formatContext->iformat->name, \"sdp\") != 0\n            || formatContext->iformat->read_packet == nullptr ||\n            formatContext->iformat->read_seek != nullptr || formatContext->iformat->read_seek2 != nullptr);\n#endif\n}\n\ntemplate<typename T>\nbool RendezVous(\n    boost::atomic_int64_t& duration,\n    RendezVousData& data,\n    unsigned int threshold,\n    bool& encountered,\n    T func)\n{\n    if (threshold == 1)\n    {\n        const auto prevDuration = duration.exchange(AV_NOPTS_VALUE);\n        if (prevDuration != AV_NOPTS_VALUE)\n        {\n            if (!func(prevDuration))\n                return false;\n            encountered = true;\n        }\n\n        return true;\n    }\n\n    if (duration == AV_NOPTS_VALUE)\n        return true;\n\n    boost::mutex::scoped_lock lock(data.mtx);\n\n    if (data.count == threshold - 1)\n    {\n        ++data.generation;\n        data.count = 0;\n        const auto prevDuration = duration.exchange(AV_NOPTS_VALUE);\n        const bool result = func(prevDuration);\n        lock.unlock();\n        data.cond.notify_all();\n        encountered = result;\n        return result;\n    }\n\n    encountered = true;\n    ++data.count;\n    const unsigned int gen = data.generation;\n    while (gen == data.generation)\n        data.cond.wait(lock);\n\n    return true;\n}\n\n} // namespace\n\nvoid FFmpegDecoder::parseRunnable(int idx)\n{\n    CHANNEL_LOG(ffmpeg_threads) << \"Parse thread started\";\n    AVPacket packet;\n    enum { UNSET, SET_EOF, SET_INVALID, REPORTED } eof = UNSET;\n\n    if (idx == 0)\n    {\n        // detect real framesize\n        fixDuration();\n\n        if (m_decoderListener != nullptr)\n        {\n            m_decoderListener->fileLoaded(m_startTime, m_duration + m_startTime);\n            m_decoderListener->changedFramePosition(m_startTime, m_startTime, m_duration + m_startTime);\n        }\n\n        startAudioThread();\n        startVideoThread();\n    }\n\n    int64_t lastTime = m_currentTime;\n    int64_t timeLeft = 0;  // effective frame time left from packet (adjusted by start_time)\n    enum { TO_RECOVER, RECOVERING, RECOVERED } recovering = RECOVERED;\n\n    const bool seekable = isSeekable(m_formatContexts[idx]);\n\n    for (;;)\n    {\n        if (boost::this_thread::interruption_requested())\n        {\n            return;\n        }\n\n        bool restarted = false;\n        RendezVous(m_seekDuration, m_seekRendezVous, m_formatContexts.size(), restarted,\n            std::bind(&FFmpegDecoder::resetDecoding, this, std::placeholders::_1, false));\n\n        if (!RendezVous(m_videoResetDuration, m_videoResetRendezVous, m_formatContexts.size(), restarted,\n            std::bind(&FFmpegDecoder::resetDecoding, this, std::placeholders::_1, true))) {\n            return;\n        }\n\n        if (restarted)\n        {\n            eof = UNSET;\n            recovering = RECOVERED;\n        }\n\n        const int readStatus = av_read_frame(m_formatContexts[idx], &packet);\n        if (readStatus >= 0)\n        {\n            const bool dispatched = dispatchPacket(idx, packet);\n            eof = UNSET;\n\n            // Compute effective frame timestamp from packet using its pts (work in stream PTS units).\n            if (seekable && packet.pts != AV_NOPTS_VALUE) {\n                const AVFormatContext* fmt = m_formatContexts[idx];\n                if (fmt && packet.stream_index >= 0 && packet.stream_index < fmt->nb_streams) {\n                    const AVStream* stream = fmt->streams[packet.stream_index];\n                    const int64_t pts = packet.pts;\n                    const int64_t dur = (packet.duration != AV_NOPTS_VALUE) ? packet.duration : 0;\n                    const int64_t start_time = (stream && stream->start_time != AV_NOPTS_VALUE) ? stream->start_time : 0;\n                    const int64_t effectiveStreamTs = pts + dur - start_time;\n\n                    if (effectiveStreamTs > 0) {\n                        // Prefer stream duration (stream PTS units)\n                        if (stream && stream->duration != AV_NOPTS_VALUE) {\n                            timeLeft = stream->duration - effectiveStreamTs;\n                        }\n                        // Fallback: use format context duration if available. Convert fmt->duration (AV_TIME_BASE units)\n                        // to the stream's time_base units before computing timeLeft.\n                        else if (fmt->duration != AV_NOPTS_VALUE && stream && stream->time_base.den != 0)\n                        {\n                            // Convert fmt->duration (AV_TIME_BASE units) to the stream's time_base units using integer rescaling.\n                            // Create an AVRational representing AV_TIME_BASE units: {1, AV_TIME_BASE}\n                            AVRational avTimeBase = { 1, AV_TIME_BASE };\n                            const int64_t fmtDurationInStreamUnits = av_rescale_q(fmt->duration, avTimeBase, stream->time_base);\n                            if (fmtDurationInStreamUnits > effectiveStreamTs)\n                            {\n                                timeLeft = fmtDurationInStreamUnits - effectiveStreamTs;\n                            }\n                            else\n                            {\n                                timeLeft = 0;\n                            }\n                        }\n                    }\n                }\n            }\n\n            if (recovering == TO_RECOVER && m_currentTime > lastTime)\n            {\n                recovering = RECOVERING;\n            }\n            else if (dispatched && recovering == RECOVERING)\n            {\n                recovering = RECOVERED;\n            }\n        }\n        else if ((readStatus == AVERROR_ECONNRESET || readStatus == AVERROR_INVALIDDATA ||\n                  timeLeft > 1) &&\n                 recovering == RECOVERED)\n        {\n            recovering = TO_RECOVER;\n            lastTime = m_currentTime;\n            timeLeft = 0;\n            if (doSeekFrame(idx, lastTime, nullptr))\n            {\n                CHANNEL_LOG(ffmpeg_seek) << __FUNCTION__ << \" Trying to recover from \" << readStatus << \"; index: \" << idx;\n            }\n            else\n            {\n                CHANNEL_LOG(ffmpeg_seek) << __FUNCTION__ << \" Can't recover from \" << readStatus << \"; index: \" << idx;\n            }\n        }\n        else\n        {\n            using namespace boost;\n            if (eof == SET_EOF || eof == SET_INVALID)\n            {\n                if ((m_decoderListener != nullptr)\n                    && m_videoPacketsQueue.empty()\n                    && m_audioPacketsQueue.empty()\n                    && (lock_guard<mutex>(m_videoFramesMutex), !m_videoFramesQueue.canPop()))\n                {\n                    if (eof == SET_EOF)\n                    {\n                        flush(idx);\n                    }\n                    if (readStatus != AVERROR_EOF && readStatus != AVERROR_ECONNRESET)\n                    {\n                        char err_buf[AV_ERROR_MAX_STRING_SIZE + 2] = \": \";\n                        CHANNEL_LOG(ffmpeg_seek) << __FUNCTION__ << \" End of stream caused by \" << readStatus\n                            << (av_strerror(readStatus, err_buf + 2, sizeof(err_buf) - 2) == 0 ? err_buf : \"\") << \"; index: \" << idx;\n                    }\n                    m_decoderListener->onEndOfStream(idx, eof == SET_INVALID);\n                    eof = REPORTED;\n                }\n            }\n            if (eof == UNSET) {\n                eof = (readStatus == AVERROR_EOF) ? SET_EOF : SET_INVALID;\n            }\n\n            this_thread::sleep_for(chrono::milliseconds(1));\n        }\n\n        // Continue packet reading loop...\n    }\n\n    CHANNEL_LOG(ffmpeg_threads) << \"Decoding ended\";\n}\n\nbool FFmpegDecoder::dispatchPacket(int idx, AVPacket& packet)\n{\n    auto guard = MakeGuard(&packet, av_packet_unref);\n\n    if (m_seekDuration != AV_NOPTS_VALUE || m_videoResetDuration != AV_NOPTS_VALUE)\n    {\n        return false;\n    }\n\n    auto seekLambda = [this, idx]\n    {\n        if (m_seekDuration != AV_NOPTS_VALUE || m_videoResetDuration != AV_NOPTS_VALUE)\n            return true;\n\n        if (m_decoderListener != nullptr)\n            m_decoderListener->onQueueFull(idx);\n\n        return false;\n    };\n\n    if (idx == m_videoContextIndex && packet.stream_index == m_videoStreamNumber)\n    { \n        if (m_videoPacketsQueue.push(packet, seekLambda))\n        {\n            guard.release();\n            return true;\n        }\n    }\n    else if (idx == m_audioContextIndex\n        && std::find(m_audioIndices.begin(), m_audioIndices.end(), packet.stream_index) != m_audioIndices.end())\n    { \n        if (m_audioPacketsQueue.push(packet, seekLambda))\n        {\n            guard.release();\n            return true;\n        }\n    }\n    else if (m_formatContexts[idx]->streams[packet.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE)\n    {\n        handleSubtitlePacket(idx, packet);\n    }\n\n    return false;\n}\n\nvoid FFmpegDecoder::handleSubtitlePacket(int idx, const AVPacket& packet)\n{\n    std::function<bool(double, double, const std::string&)> addIntervalCallback;\n    {\n        boost::lock_guard<boost::mutex> locker(m_addIntervalMutex);\n        if (m_subtitleIdx == -1 || !m_addIntervalCallback)\n            return;\n\n        const auto& subtitleItem = m_subtitleItems.at(m_subtitleIdx);\n        if (subtitleItem.contextIdx != idx || subtitleItem.streamIdx != packet.stream_index)\n            return;\n\n        addIntervalCallback = m_addIntervalCallback;\n\n        if (m_subtitlesCodecContext == nullptr)\n        {\n            m_subtitlesCodecContext = MakeSubtitlesCodecContext(\n                m_formatContexts[idx]->streams[packet.stream_index]->codecpar);\n            if (m_subtitlesCodecContext == nullptr)\n            {\n                return;\n            }\n        }\n    }\n\n    std::string text = GetSubtitle(m_subtitlesCodecContext, packet);\n    if (!text.empty())\n    {\n        // Convert subtitle pts/duration to seconds using the subtitle stream time_base.\n        const AVFormatContext* fmt = m_formatContexts[idx];\n        if (fmt && packet.stream_index >= 0 && packet.stream_index < fmt->nb_streams)\n        {\n            const AVStream* s = fmt->streams[packet.stream_index];\n            if (s && packet.pts != AV_NOPTS_VALUE)\n            {\n                double startSec = av_q2d(s->time_base) * static_cast<double>(packet.pts);\n                double endSec = (packet.duration != AV_NOPTS_VALUE)\n                    ? av_q2d(s->time_base) * static_cast<double>(packet.pts + packet.duration)\n                    : startSec;\n\n                if (!addIntervalCallback(startSec, endSec, text))\n                {\n                    boost::lock_guard<boost::mutex> locker(m_addIntervalMutex);\n\n                    m_subtitleIdx = -1;\n                    m_addIntervalCallback = {};\n                    avcodec_free_context(&m_subtitlesCodecContext);\n                }\n            }\n        }\n    }\n}\n\nvoid FFmpegDecoder::flush(int idx)\n{\n    if (m_videoStreamNumber >= 0 && m_videoContextIndex == idx)\n    {\n        AVPacket packet{};\n        packet.stream_index = m_videoStreamNumber;\n        packet.pts = AV_NOPTS_VALUE;\n        packet.dts = AV_NOPTS_VALUE;\n        dispatchPacket(m_videoContextIndex, packet);\n    }\n    if (m_audioStreamNumber >= 0 && m_audioContextIndex == idx)\n    {\n        AVPacket packet{};\n        packet.stream_index = m_audioStreamNumber;\n        packet.pts = AV_NOPTS_VALUE;\n        packet.dts = AV_NOPTS_VALUE;\n        dispatchPacket(m_audioContextIndex, packet);\n    }\n}\n\nvoid FFmpegDecoder::startAudioThread()\n{\n    if (m_audioStreamNumber >= 0)\n    {\n        m_mainAudioThread = std::make_unique<boost::thread>(&FFmpegDecoder::audioParseRunnable, this);\n    }\n}\n\nvoid FFmpegDecoder::startVideoThread()\n{\n    if (m_videoStreamNumber >= 0)\n    {\n        m_mainVideoThread = std::make_unique<boost::thread>(&FFmpegDecoder::videoParseRunnable, this);\n    }\n}\n\nbool FFmpegDecoder::resetDecoding(int64_t seekDuration, bool resetVideo)\n{\n    CHANNEL_LOG(ffmpeg_seek) << __FUNCTION__ << \" resetVideo=\" << resetVideo;\n\n    AVPacket packet{};\n    auto guard = MakeGuard(&packet, av_packet_unref);\n\n    for (int i = 0; i < m_formatContexts.size(); ++i)\n    {\n        if (!doSeekFrame(i, seekDuration, resetVideo ? nullptr : &packet))\n            return false;\n    }\n\n    if (!respawn(seekDuration, resetVideo))\n        return false;\n\n    if (packet.data != nullptr)\n    {\n        guard.release();\n        dispatchPacket(m_videoContextIndex, packet);\n    }\n\n    return true;\n}\n\nbool FFmpegDecoder::doSeekFrame(int idx, int64_t seekDuration, AVPacket* packet)\n{\n    if (idx != m_audioContextIndex && !basedOnVideoStream())\n        return true;  // continue;\n\n    auto formatContext = m_formatContexts[idx];\n    if (!isSeekable(formatContext))\n        return true;//continue;\n\n    const int64_t currentTime = m_currentTime;\n    const bool handlingPrevFrame = m_isPaused && seekDuration == currentTime\n        && packet != nullptr && m_videoContextIndex != -1;\n\n    if (handlingPrevFrame)\n    {\n        const auto threshold\n            = m_videoStream->avg_frame_rate.den * m_videoStream->time_base.den\n            / (2LL * m_videoStream->avg_frame_rate.num * m_videoStream->time_base.num);\n        seekDuration -= threshold;\n    }\n\n    const bool backward = seekDuration < currentTime;\n    const int streamNumber = (idx == m_videoContextIndex && basedOnVideoStream())\n                                 ? m_videoStreamNumber\n                                 : m_audioStreamNumber.load();\n\n    auto convertedSeekDuration = seekDuration;\n    if (handlingPrevFrame)\n    {\n        convertedSeekDuration = (std::max)(m_startTime, \n            convertedSeekDuration - m_videoStream->time_base.den / m_videoStream->time_base.num);\n    }\n    if (idx != m_videoContextIndex && m_videoContextIndex != -1)\n    {\n        convertedSeekDuration = av_rescale_q(convertedSeekDuration, m_videoStream->time_base, m_audioStream->time_base);\n    }\n\n    if (handlingPrevFrame)\n    {\n        if (av_seek_frame(formatContext, streamNumber, convertedSeekDuration, AVSEEK_FLAG_BACKWARD) < 0)\n        {\n            CHANNEL_LOG(ffmpeg_seek) << \"Seek failed\";\n            return false;\n        }\n    }\n    else\n    {\n        if (av_seek_frame(formatContext, streamNumber, convertedSeekDuration, 0) < 0\n            && ((convertedSeekDuration >= 0\n                ? av_seek_frame(formatContext, streamNumber, convertedSeekDuration, AVSEEK_FLAG_BACKWARD)\n                : av_seek_frame(formatContext, streamNumber, 0, 0)) < 0))\n        {\n            CHANNEL_LOG(ffmpeg_seek) << \"Seek failed\";\n            return false;\n        }\n    }\n\n    if (packet && backward && idx == m_videoContextIndex && convertedSeekDuration > m_startTime)\n    {\n        const int readStatus = av_read_frame(formatContext, packet);\n        if (readStatus >= 0)\n        {\n            auto pts = packet->pts;\n            if (pts != AV_NOPTS_VALUE)\n            {\n                if (packet->stream_index != m_videoStreamNumber)\n                {\n                    const auto& time_base = formatContext->streams[packet->stream_index]->time_base;\n                    pts = (time_base.den && time_base.num)\n                        ? av_rescale_q(pts, time_base, m_videoStream->time_base) : 0;\n                    if (handlingPrevFrame)\n                        pts += m_videoStream->avg_frame_rate.den * m_videoStream->time_base.den\n                        / (2LL * m_videoStream->avg_frame_rate.num * m_videoStream->time_base.num);\n                }\n                if (pts >= currentTime)\n                {\n                    const int flags = handlingPrevFrame ? AVSEEK_FLAG_BACKWARD : 0;\n                    av_packet_unref(packet);\n                    if (av_seek_frame(formatContext, streamNumber, m_startTime, flags) < 0\n                        || av_seek_frame(formatContext, streamNumber, convertedSeekDuration, flags) < 0)\n                    {\n                        CHANNEL_LOG(ffmpeg_seek) << \"Seek correction failed\";\n                        return false;\n                    }\n                }\n            }\n        }\n    }\n\n    if (handlingPrevFrame)\n    {\n        m_prevTime = seekDuration;\n        m_isVideoSeekingWhilePaused = true;\n    }\n\n    return true;\n}\n\nbool FFmpegDecoder::respawn(int64_t seekDuration, bool resetVideo)\n{\n    const bool hasVideo = m_mainVideoThread != nullptr;\n    const bool hasAudio = m_mainAudioThread != nullptr;\n\n    if (hasVideo)\n    {\n        m_mainVideoThread->interrupt();\n    }\n    if (hasAudio)\n    {\n        m_mainAudioThread->interrupt();\n    }\n\n    if (hasVideo)\n    {\n        m_mainVideoThread->join();\n    }\n    if (hasAudio)\n    {\n        m_mainAudioThread->join();\n    }\n\n    // Reset stuff\n    m_videoPacketsQueue.clear();\n    m_audioPacketsQueue.clear();\n\n    m_mainDisplayThread->interrupt();\n    m_mainDisplayThread->join();\n\n    // Free videoFrames\n    {\n        boost::lock_guard<boost::mutex> locker(m_videoFramesMutex);\n        m_videoFramesQueue.clear();\n        m_frameDisplayingRequested = false;\n        ++m_generation;\n    }\n\n    m_videoResetting = false;\n\n    m_videoStartClock = VIDEO_START_CLOCK_NOT_INITIALIZED;\n\n    if (resetVideo && !resetVideoProcessing())\n    {\n        return false;\n    }\n\n    m_mainDisplayThread = std::make_unique<boost::thread>(&FFmpegDecoder::displayRunnable, this);\n\n    if (hasVideo)\n    {\n        if (m_videoCodecContext != nullptr) {\n            avcodec_flush_buffers(m_videoCodecContext);\n        }\n    }\n    if (hasAudio)\n    {\n        if (m_audioCodecContext != nullptr) {\n            avcodec_flush_buffers(m_audioCodecContext);\n        }\n        m_audioPlayer->WaveOutReset();\n    }\n\n    if (m_decoderListener != nullptr)\n    {\n        m_decoderListener->changedFramePosition(m_startTime, seekDuration, m_duration + m_startTime);\n    }\n\n    seekWhilePaused();\n\n    // Restart\n    startAudioThread();\n    startVideoThread();\n\n    return true;\n}\n\nvoid FFmpegDecoder::fixDuration()\n{\n    if (m_duration <= 0)\n    {\n        const int streamNumber =\n            (m_videoContextIndex == 0) ? m_videoStreamNumber : m_audioStreamNumber.load();\n\n        m_duration = 0;\n        if (!isSeekable(m_formatContexts[0]))\n        {\n            return;\n        }\n\n        AVPacket packet;\n        while (av_read_frame(m_formatContexts[0], &packet) >= 0)\n        {\n            if (packet.stream_index == streamNumber)\n            {\n                if (packet.pts != AV_NOPTS_VALUE)\n                {\n                    m_duration = packet.pts;\n                }\n                else if (packet.dts != AV_NOPTS_VALUE)\n                {\n                    m_duration = packet.dts;\n                }\n            }\n            av_packet_unref(&packet);\n\n            if (boost::this_thread::interruption_requested())\n            {\n                CHANNEL_LOG(ffmpeg_threads) << \"Parse thread broken\";\n                return;\n            }\n        }\n\n        if (avformat_seek_file(m_formatContexts[0], streamNumber, 0, 0, 0,\n                               AVSEEK_FLAG_FRAME) < 0)\n        {\n            CHANNEL_LOG(ffmpeg_seek) << \"Seek failed\";\n            return;\n        }\n    }\n}\n"
  },
  {
    "path": "video/subtitles.cpp",
    "content": "#include \"subtitles.h\"\n\n#include \"makeguard.h\"\n\n#include <boost/algorithm/string/predicate.hpp>\n#include <boost/algorithm/string.hpp>\n\nnamespace {\n\n/*\n *  from mpv/sub/sd_ass.c\n * ass_to_plaintext() was written by wm4 and he says it can be under LGPL\n */\nstd::string ass_to_plaintext(const char *in)\n{\n    std::string result;\n\n    bool in_tag = false;\n    const char *open_tag_pos = nullptr;\n    bool in_drawing = false;\n    while (*in) {\n        if (in_tag) {\n            if (in[0] == '}') {\n                in += 1;\n                in_tag = false;\n            } else if (in[0] == '\\\\' && in[1] == 'p') {\n                in += 2;\n                // Skip text between \\pN and \\p0 tags. A \\p without a number\n                // is the same as \\p0, and leading 0s are also allowed.\n                in_drawing = false;\n                while (in[0] >= '0' && in[0] <= '9') {\n                    if (in[0] != '0')\n                        in_drawing = true;\n                    in += 1;\n                }\n            } else {\n                in += 1;\n            }\n        } else {\n            if (in[0] == '\\\\' && (in[1] == 'N' || in[1] == 'n')) {\n                in += 2;\n                result += '\\n';\n            } else if (in[0] == '\\\\' && in[1] == 'h') {\n                in += 2;\n                result += ' ';\n            } else if (in[0] == '{') {\n                open_tag_pos = in;\n                in += 1;\n                in_tag = true;\n            } else {\n                if (!in_drawing)\n                    result += in[0];\n                in += 1;\n            }\n        }\n    }\n    // A '{' without a closing '}' is always visible.\n    if (in_tag) {\n        result += open_tag_pos;\n    }\n\n    return result;\n}\n\nstd::string fromAss(const char* ass) {\n    auto b = ass_to_plaintext(ass);\n    int hour1, min1, sec1, hunsec1,hour2, min2, sec2, hunsec2;\n    char line[1024];\n    // fixme: \"\\0\" maybe not allowed\n    if (sscanf(b.c_str(), \"Dialogue: Marked=%*d,%d:%d:%d.%d,%d:%d:%d.%d%1023[^\\r\\n]\", //&nothing,\n                            &hour1, &min1, &sec1, &hunsec1,\n                            &hour2, &min2, &sec2, &hunsec2,\n                            line) < 9)\n        if (sscanf(b.c_str(), \"Dialogue: %*d,%d:%d:%d.%d,%d:%d:%d.%d%1023[^\\r\\n]\", //&nothing,\n                &hour1, &min1, &sec1, &hunsec1,\n                &hour2, &min2, &sec2, &hunsec2,\n                line) < 9)\n            if (sscanf(b.c_str(), \"%d,%d%1023[^\\r\\n]\",  //&nothing,\n                       &sec1, &sec2, line) < 3)\n                return b;  // libass ASS_Event.Text has no Dialogue\n    auto ret = strchr(line, ',');\n    if (!ret)\n        return line;\n    static const char kDefaultStyle[] = \"Default,\";\n    for (int comma = 0; comma < 6; comma++) {\n        if (!(ret = strchr(++ret, ','))) {\n            // workaround for ffmpeg decoded srt in ass format: \"Dialogue: 0,0:42:29.20,0:42:31.08,Default,Chinese\\NEnglish.\n            if (!(ret = strstr(line, kDefaultStyle))) {\n                if (line[0] == ',') //work around for libav-9-\n                    return line + 1;\n                return line;\n            }\n            ret += sizeof(kDefaultStyle) - 1 - 1; // tail \\0\n        }\n    }\n    ret++;\n    const auto p = strcspn(b.c_str(), \"\\r\\n\");\n    if (p == b.size()) //not found\n        return ret;\n\n    std::string line2 = b.substr(p + 1);\n    boost::algorithm::trim(line2);\n    if (line2.empty())\n        return ret;\n\n    return ret + (\"\\n\" + line2);\n}\n\n} // namespace\n\nAVCodecContext* MakeSubtitlesCodecContext(AVCodecParameters* codecpar)\n{\n    auto codecContext = avcodec_alloc_context3(nullptr);\n    if (codecContext == nullptr) {\n        return nullptr;\n    }\n\n    auto codecContextGuard = MakeGuard(&codecContext, avcodec_free_context);\n\n    if (avcodec_parameters_to_context(codecContext, codecpar) < 0) {\n        return nullptr;\n    }\n\n    auto codec = avcodec_find_decoder(codecContext->codec_id);\n    if (codec == nullptr)\n    {\n        return nullptr;  // Codec not found\n    }\n\n    // Open codec\n    if (avcodec_open2(codecContext, codec, nullptr) < 0)\n    {\n        assert(false && \"Error on codec opening\");\n        return nullptr;  // Could not open codec\n    }\n\n    codecContextGuard.release();\n\n    return codecContext;\n}\n\nstd::string GetSubtitle(AVCodecContext* ctx, const AVPacket& packet)\n{\n    AVSubtitle sub{};\n\n    auto subtitleGuard = MakeGuard(&sub, avsubtitle_free);\n\n    int got_subtitle = 0;\n    int ret = avcodec_decode_subtitle2(ctx, &sub, &got_subtitle, const_cast<AVPacket*>(&packet));\n    if (ret >= 0 && got_subtitle)\n    {\n        std::string text;\n\n        for (unsigned i = 0; i < sub.num_rects; i++) {\n            switch (sub.rects[i]->type) {\n            case SUBTITLE_ASS:\n                text += fromAss(sub.rects[i]->ass);\n                text += '\\n';\n                break;\n            case SUBTITLE_TEXT:\n                text += sub.rects[i]->text;\n                text += '\\n';\n                break;\n            default:\n                break;\n            }\n        }\n\n        return text;\n    }\n\n    return {};\n}\n"
  },
  {
    "path": "video/subtitles.h",
    "content": "#pragma once\n\nextern \"C\" {\n#include <libavcodec/avcodec.h>\n}\n\n#include <string>\n\nAVCodecContext* MakeSubtitlesCodecContext(AVCodecParameters* codecpar);\nstd::string GetSubtitle(AVCodecContext* ctx, const AVPacket& packet);\n"
  },
  {
    "path": "video/video.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <ProjectGuid>{3013C140-DDFC-4BF4-9091-0C4131A0D2A6}</ProjectGuid>\n    <Keyword>Win32Proj</Keyword>\n    <RootNamespace>video</RootNamespace>\n    <ProjectName>video</ProjectName>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>StaticLibrary</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"PropertySheets\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" />\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>NOMINMAX;WIN32;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0602;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>NOMINMAX;WIN32;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0602;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NOMINMAX;WIN32;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0602;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>\n      </PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>NOMINMAX;WIN32;_CRT_SECURE_NO_WARNINGS;_WIN32_WINNT=0x0602;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <AdditionalIncludeDirectories>%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <GenerateDebugInformation>true</GenerateDebugInformation>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n    </Link>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <ClCompile Include=\"audioparserunnable.cpp\" />\n    <ClCompile Include=\"decoderiocontext.cpp\" />\n    <ClCompile Include=\"displayrunnable.cpp\" />\n    <ClCompile Include=\"ffmpegdecoder.cpp\" />\n    <ClCompile Include=\"ffmpeg_dxva2.cpp\" />\n    <ClCompile Include=\"parserunnable.cpp\" />\n    <ClCompile Include=\"subtitles.cpp\" />\n    <ClCompile Include=\"videoparserunnable.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"audioplayer.h\" />\n    <ClInclude Include=\"decoderiocontext.h\" />\n    <ClInclude Include=\"ffmpegdecoder.h\" />\n    <ClInclude Include=\"ffmpeg_dxva2.h\" />\n    <ClInclude Include=\"fqueue.h\" />\n    <ClInclude Include=\"decoderinterface.h\" />\n    <ClInclude Include=\"interlockedadd.h\" />\n    <ClInclude Include=\"makeguard.h\" />\n    <ClInclude Include=\"ordered_scoped_token.h\" />\n    <ClInclude Include=\"subtitles.h\" />\n    <ClInclude Include=\"videoframe.h\" />\n    <ClInclude Include=\"vqueue.h\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "video/video.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"audioparserunnable.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"displayrunnable.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ffmpegdecoder.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"parserunnable.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"videoparserunnable.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ffmpeg_dxva2.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"subtitles.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"decoderiocontext.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"audioplayer.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ffmpegdecoder.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"fqueue.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"decoderinterface.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"makeguard.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"videoframe.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"vqueue.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ffmpeg_dxva2.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"interlockedadd.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"subtitles.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"decoderiocontext.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ordered_scoped_token.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n  </ItemGroup>\n  <ItemGroup>\n  </ItemGroup>\n  <ItemGroup>\n  </ItemGroup>\n  <ItemGroup>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "video/videoframe.h",
    "content": "#pragma once\n\n#include <memory>\n#include <future>\n\nstruct AVFrameDeleter\n{\n    void operator()(AVFrame *frame) const { av_frame_free(&frame); };\n};\n\ntypedef std::unique_ptr<AVFrame, AVFrameDeleter> AVFramePtr;\n\nstruct VideoFrame\n{\n    double m_pts{0};\n    int64_t m_duration{0};\n    AVFramePtr m_image;\n    std::future<bool> m_convert;\n\n    VideoFrame() \n        : m_image(av_frame_alloc()) \n    {}\n\n    VideoFrame(const VideoFrame&) = delete;\n    VideoFrame& operator=(const VideoFrame&) = delete;\n\n    void free()\n    {\n        m_convert = {}; // Finish first\n        av_frame_unref(m_image.get());\n    }\n    void realloc(AVPixelFormat pix_fmt, int width, int height)\n    {\n        if (pix_fmt != m_image->format || width != m_image->width || height != m_image->height\n            || !av_frame_is_writable(m_image.get()))\n        {\n            av_frame_unref(m_image.get());\n\n            m_image->format = pix_fmt;\n            m_image->width = width;\n            m_image->height = height;\n            av_frame_get_buffer(m_image.get(), 16);\n        }\n    }\n};\n"
  },
  {
    "path": "video/videoparserunnable.cpp",
    "content": "#include \"ffmpegdecoder.h\"\n#include \"makeguard.h\"\n#include \"interlockedadd.h\"\n\nextern \"C\"\n{\n#include \"libavutil/imgutils.h\"\n}\n\n#include <boost/log/trivial.hpp>\n#include <tuple>\n\nnamespace {\n\n#ifdef _MSC_VER\n\n#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)\n\ninline uint8_t clamp255(uint32_t v) {\n    const uint8_t noOverflowCandidate = v;\n    return (noOverflowCandidate == v) ? noOverflowCandidate : 255;\n}\n\n#define C16TO8(v, scale) clamp255(((v) * (scale)) >> 16)\n\n/*\nasm volatile (\n  \"movd      %3,%%xmm2                      \\n\"\n  \"punpcklwd %%xmm2,%%xmm2                  \\n\"\n  \"pshufd    $0x0,%%xmm2,%%xmm2             \\n\"\n\n  // 32 pixels per loop.\n  LABELALIGN\n  \"1:                                       \\n\"\n  \"movdqu    (%0),%%xmm0                    \\n\"\n  \"movdqu    0x10(%0),%%xmm1                \\n\"\n  \"add       $0x20,%0                       \\n\"\n  \"pmulhuw   %%xmm2,%%xmm0                  \\n\"\n  \"pmulhuw   %%xmm2,%%xmm1                  \\n\"\n  \"packuswb  %%xmm1,%%xmm0                  \\n\"\n  \"movdqu    %%xmm0,(%1)                    \\n\"\n  \"add       $0x10,%1                       \\n\"\n  \"sub       $0x10,%2                       \\n\"\n  \"jg        1b                             \\n\"\n: \"+r\"(src_y),   // %0\n  \"+r\"(dst_y),   // %1\n  \"+r\"(width)    // %2\n: \"r\"(scale)     // %3\n: \"memory\", \"cc\", \"xmm0\", \"xmm1\", \"xmm2\");\n*/\n\nconst auto DITHER_SCALE = 16352;\n\n// Use scale to convert lsb formats to msb, depending how many bits there are:\n// 32768 = 9 bits\n// 16384 = 10 bits (dither - 16352)\n// 4096 = 12 bits\n// 256 = 16 bits\nvoid Convert16To8Row_SSSE3(const __m128i* src_y,\n    __m128i* dst_y,\n    int scale,\n    int width,\n    int32_t odd_even_add /*either 0x00000002 or 0x00030001*/) {\n\n    // Load scale factor into SIMD register\n    __m128i s = _mm_cvtsi32_si128(scale);\n    s = _mm_unpacklo_epi16(s, s);\n    s = _mm_shuffle_epi32(s, 0);\n\n    // Broadcast 32-bit odd/even offset across the 128-bit register (four times)\n    __m128i odd_even_offset = _mm_set1_epi32(odd_even_add);\n\n    for (; width > 0; width -= 16)\n    {\n        // Load 16-bit grayscale values from the source buffer\n        __m128i a0 = *src_y++;\n        __m128i a1 = *src_y++;\n\n        // Apply alternating Bayer mask values using the fully populated 128-bit register\n        a0 = _mm_add_epi16(a0, odd_even_offset);\n        a1 = _mm_add_epi16(a1, odd_even_offset);\n\n        // Scale down from 16-bit to 8-bit using multiply-high\n        a0 = _mm_mulhi_epu16(a0, s);\n        a1 = _mm_mulhi_epu16(a1, s);\n\n        // Pack two 16-bit sets into one 8-bit register\n        a0 = _mm_packus_epi16(a0, a1);\n\n        // Store the final 8-bit pixels into the destination buffer\n        *dst_y++ = a0;\n    }\n}\n\nvoid ScaleRowDown2_16To8_C(const uint16_t* src_ptr,\n    ptrdiff_t src_stride,\n    uint8_t* dst,\n    int dst_width,\n    int scale) {\n    int x;\n    (void)src_stride;\n    assert(scale >= 256);\n    assert(scale <= 32768);\n    for (x = 0; x < dst_width - 1; x += 2) {\n        dst[0] = C16TO8(src_ptr[1], scale);\n        dst[1] = C16TO8(src_ptr[3], scale);\n        dst += 2;\n        src_ptr += 4;\n    }\n    if (dst_width & 1) {\n        dst[0] = C16TO8(src_ptr[1], scale);\n    }\n}\n\nvoid Convert16To8Row_Any_SSSE3(const uint16_t* src_ptr, uint8_t* dst_ptr, int scale, int width, int y) \n{\n    enum {\n          SBPP = 2, \n          BPP = 1,\n          MASK = 15,\n    };\n\n    const int r = width & MASK;                            \n    const int n = width & ~MASK;\n    const int32_t add = (scale != DITHER_SCALE) ? 0 : ((y & 1) ? 0x00000002 : 0x00030001);\n    if (n > 0) {                                     \n        Convert16To8Row_SSSE3((const __m128i*)src_ptr, (__m128i*)dst_ptr, scale, n, add);\n    }     \n    if (r > 0) {\n        __declspec(align(16)) uint16_t temp[32];\n        __declspec(align(16)) uint8_t out[32];\n        memset(temp, 0, 32 * SBPP); /* for msan */\n        memcpy(temp, src_ptr + n, r * SBPP);\n        Convert16To8Row_SSSE3((const __m128i*)temp, (__m128i*)out, scale, MASK + 1, add);\n        memcpy(dst_ptr + n, out, r * BPP);\n    }\n}\n\nvoid Convert16To8Plane(const uint16_t* src_y,\n                       int src_stride_y,\n                       uint8_t* dst_y,\n                       int dst_stride_y,\n                       int scale,  // 16384 for 10 bits\n                       int width,\n                       int height) \n{\n  // Negative height means invert the image.\n  if (height < 0) {\n    height = -height;\n    dst_y = dst_y + (height - 1) * dst_stride_y;\n    dst_stride_y = -dst_stride_y;\n  }\n  // Coalesce rows.\n  if (src_stride_y == width && dst_stride_y == width) {\n    width *= height;\n    height = 1;\n    src_stride_y = dst_stride_y = 0;\n  }\n\n  // Convert plane\n  for (int y = 0; y < height; ++y) {\n      Convert16To8Row_Any_SSSE3(src_y, dst_y, scale, width, y);\n    src_y += src_stride_y;\n    dst_y += dst_stride_y;\n  }\n}\n\nvoid ScalePlaneDown2_16To8(int dst_width,\n                        int dst_height,\n                        int src_stride,\n                        int dst_stride,\n                        const uint16_t* src_ptr,\n                        uint8_t* dst_ptr,\n                        int scale) {\n    int row_stride = src_stride * 2;\n    //if (!filtering) {\n        src_ptr += src_stride;  // Point to odd rows.\n        src_stride = 0;\n    //}\n\n    for (int y = 0; y < dst_height; ++y) {\n        ScaleRowDown2_16To8_C(src_ptr, src_stride, dst_ptr, dst_width, scale);\n        src_ptr += row_stride;\n        dst_ptr += dst_stride;\n    }\n}\n\nint I010ToI420(const uint16_t* src_y,\n               int src_stride_y,\n               const uint16_t* src_u,\n               int src_stride_u,\n               const uint16_t* src_v,\n               int src_stride_v,\n               uint8_t* dst_y,\n               int dst_stride_y,\n               uint8_t* dst_u,\n               int dst_stride_u,\n               uint8_t* dst_v,\n               int dst_stride_v,\n               int width,\n               int height)\n{\n  int halfwidth = (width + 1) >> 1;\n  int halfheight = (height + 1) >> 1;\n  if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {\n    return -1;\n  }\n  // Negative height means invert the image.\n  if (height < 0) {\n    height = -height;\n    halfheight = (height + 1) >> 1;\n    src_y = src_y + (height - 1) * src_stride_y;\n    src_u = src_u + (halfheight - 1) * src_stride_u;\n    src_v = src_v + (halfheight - 1) * src_stride_v;\n    src_stride_y = -src_stride_y;\n    src_stride_u = -src_stride_u;\n    src_stride_v = -src_stride_v;\n  }\n\n  // Convert Y plane.\n  Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, DITHER_SCALE, width,\n                    height);\n  // Convert UV planes.\n  Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, 16384, halfwidth,\n                    halfheight);\n  Convert16To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, 16384, halfwidth,\n                    halfheight);\n  return 0;\n}\n\nint I410ToI420(const uint16_t* src_y,\n            int src_stride_y,\n            const uint16_t* src_u,\n            int src_stride_u,\n            const uint16_t* src_v,\n            int src_stride_v,\n            uint8_t* dst_y,\n            int dst_stride_y,\n            uint8_t* dst_u,\n            int dst_stride_u,\n            uint8_t* dst_v,\n            int dst_stride_v,\n            int width,\n            int height) {\n    const int depth = 10;\n    const int scale = 1 << (24 - depth);\n\n    if (width <= 0 || height == 0) {\n        return -1;\n    }\n    // Negative height means invert the image.\n    if (height < 0) {\n        height = -height;\n        src_y = src_y + (height - 1) * src_stride_y;\n        src_u = src_u + (height - 1) * src_stride_u;\n        src_v = src_v + (height - 1) * src_stride_v;\n        src_stride_y = -src_stride_y;\n        src_stride_u = -src_stride_u;\n        src_stride_v = -src_stride_v;\n    }\n\n    {\n        const int uv_width = SUBSAMPLE(width, 1, 1);\n        const int uv_height = SUBSAMPLE(height, 1, 1);\n\n        Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, DITHER_SCALE, width,\n            height);\n        ScalePlaneDown2_16To8(uv_width, uv_height, src_stride_u,\n            dst_stride_u, src_u, dst_u, scale);\n        ScalePlaneDown2_16To8(uv_width, uv_height, src_stride_v,\n            dst_stride_v, src_v, dst_v, scale);\n    }\n    return 0;\n}\n\n#endif\n\nbool frameToImage(\n    VideoFrame& videoFrameData,\n    AVFramePtr& videoFrame,\n    SwsContext*& imageCovertContext,\n    AVPixelFormat pixelFormat)\n{\n    if (videoFrame->format == AV_PIX_FMT_NONE)\n    {\n        return false;\n    }\n\n    if (videoFrame->format == pixelFormat\n        || videoFrame->format == AV_PIX_FMT_DXVA2_VLD)\n    {\n        std::swap(videoFrame, videoFrameData.m_image);\n    }\n    else\n    {\n        const int width = videoFrame->width;\n        const int height = videoFrame->height;\n\n        videoFrameData.realloc(pixelFormat, width, height);\n\n#ifdef _MSC_VER\n        if ((videoFrame->format == AV_PIX_FMT_YUV420P10LE || videoFrame->format == AV_PIX_FMT_YUV444P10LE) && pixelFormat == AV_PIX_FMT_YUV420P\n            && !((intptr_t(videoFrame->data[0]) & 15) || (videoFrame->linesize[0] & 15)\n            || (intptr_t(videoFrame->data[1]) & 15) || (videoFrame->linesize[1] & 15)\n            || (intptr_t(videoFrame->data[2]) & 15) || (videoFrame->linesize[2] & 15)))\n        {\n            if (videoFrame->format == AV_PIX_FMT_YUV420P10LE)\n            {\n                I010ToI420(\n                    (const uint16_t*)videoFrame->data[0],\n                    videoFrame->linesize[0] / 2,\n                    (const uint16_t*)videoFrame->data[1],\n                    videoFrame->linesize[1] / 2,\n                    (const uint16_t*)videoFrame->data[2],\n                    videoFrame->linesize[2] / 2,\n                    videoFrameData.m_image->data[0],\n                    videoFrameData.m_image->linesize[0],\n                    videoFrameData.m_image->data[1],\n                    videoFrameData.m_image->linesize[1],\n                    videoFrameData.m_image->data[2],\n                    videoFrameData.m_image->linesize[2],\n                    width, height\n                );\n            }\n            else\n            {\n                I410ToI420(\n                    (const uint16_t*)videoFrame->data[0],\n                    videoFrame->linesize[0] / 2,\n                    (const uint16_t*)videoFrame->data[1],\n                    videoFrame->linesize[1] / 2,\n                    (const uint16_t*)videoFrame->data[2],\n                    videoFrame->linesize[2] / 2,\n                    videoFrameData.m_image->data[0],\n                    videoFrameData.m_image->linesize[0],\n                    videoFrameData.m_image->data[1],\n                    videoFrameData.m_image->linesize[1],\n                    videoFrameData.m_image->data[2],\n                    videoFrameData.m_image->linesize[2],\n                    width, height\n                );\n            }\n        }\n        else\n#endif\n        {\n            // Prepare image conversion\n            imageCovertContext =\n                sws_getCachedContext(imageCovertContext, videoFrame->width, videoFrame->height,\n                    static_cast<AVPixelFormat>(videoFrame->format), width, height, pixelFormat,\n                    0, nullptr, nullptr, nullptr);\n\n            assert(imageCovertContext != nullptr);\n\n            if (imageCovertContext == nullptr)\n            {\n                return false;\n            }\n\n            // Doing conversion\n            if (sws_scale(imageCovertContext, videoFrame->data, videoFrame->linesize, 0,\n                videoFrame->height, videoFrameData.m_image->data, videoFrameData.m_image->linesize) <= 0)\n            {\n                assert(false && \"sws_scale failed\");\n                BOOST_LOG_TRIVIAL(error) << \"sws_scale failed\";\n                return false;\n            }\n        }\n\n        videoFrameData.m_image->sample_aspect_ratio = videoFrame->sample_aspect_ratio;\n    }\n\n    return true;\n}\n\nauto GetAsyncConversionFunction(OrderedScopedTokenGenerator::Token t,\n    AVFramePtr input,\n    std::promise<VideoFrame *> &videoFramePromise,\n    boost::shared_ptr<IFrameDecoder::ImageConversionFunc> imageConversionFunc,\n    AVPixelFormat pixelFormat)\n{\n    return [t = std::move(t), input = std::move(input),\n        outputFut = videoFramePromise.get_future(),\n        imageConversionFunc = std::move(imageConversionFunc),\n        pixelFormat]() mutable\n    {\n        try {\n            if (input->format == AV_PIX_FMT_NONE)\n                return false;\n\n            const int stride = (input->width + 1) & ~1;\n\n            std::vector<uint8_t> img(stride * (input->height + (input->height + 1) / 2));\n\n            const auto data = img.data();\n\n            if (input->format == AV_PIX_FMT_NV12)\n            {\n                av_image_copy_plane(data, stride, input->data[0], input->linesize[0], input->width, input->height);\n                av_image_copy_plane(data + stride * input->height, stride, input->data[1], input->linesize[1], input->width, input->height / 2);\n            }\n            else\n            {\n                auto img_convert_ctx = sws_getContext(\n                    input->width,\n                    input->height,\n                    (AVPixelFormat)input->format,\n                    input->width,\n                    input->height,\n                    AV_PIX_FMT_NV12,\n                    SWS_FAST_BILINEAR, NULL, NULL, NULL);\n\n                uint8_t* const dst[] = { data, data + stride * input->height };\n                const int dstStride[] = { stride, stride };\n\n                sws_scale(img_convert_ctx, input->data, input->linesize, 0, input->height,\n                    dst, dstStride);\n\n                sws_freeContext(img_convert_ctx);\n            }\n\n            const auto width = input->width;\n            const auto height = input->height;\n            const auto pts = input->pts;\n\n            input.reset();  // Free input frame as soon as possible since it's not needed anymore\n\n            std::vector<uint8_t> outputImg;\n\n            int outputHeight{};\n            int outputWidth{};\n\n            if (!(*imageConversionFunc)(std::move(t), data, stride, width, height,\n                pts, outputImg, outputWidth, outputHeight))\n            {\n                return false;\n            }\n\n            const int outputStride = outputWidth;\n\n            auto output = outputFut.get();\n            if (!output)\n                return false;\n\n            output->realloc(pixelFormat, outputWidth, outputHeight);\n\n            auto img_convert_ctx = sws_getContext(\n                outputWidth,\n                outputHeight,\n                AV_PIX_FMT_NV12,\n                outputWidth,\n                outputHeight,\n                pixelFormat,\n                SWS_FAST_BILINEAR, NULL, NULL, NULL);\n\n            const auto outputData = outputImg.data();\n\n            uint8_t* const src[] = { outputData, outputData + outputStride * outputHeight };\n            const int srcStride[] = { outputStride, outputStride };\n\n            sws_scale(img_convert_ctx,\n                src, srcStride,\n                0, outputHeight,\n                output->m_image->data,\n                output->m_image->linesize);\n\n            sws_freeContext(img_convert_ctx);\n        }\n        catch (const std::exception& ex) {\n            CHANNEL_LOG(ffmpeg_sync) << \"Exception in async converter: \" << typeid(ex).name() << \": \" << ex.what();\n            return false;\n        }\n\n        return true;\n    };\n}\n\n} // namespace\n\nstruct FFmpegDecoder::VideoParseContext\n{\n    bool initialized = false;\n    int numSkipped = 0;\n    OrderedScopedTokenGenerator tokenGenerator;\n    AVFramePtr prevVideoFrame;\n};\n\nvoid FFmpegDecoder::videoParseRunnable()\n{\n    CHANNEL_LOG(ffmpeg_threads) << \"Video thread started\";\n    m_videoStartClock = VIDEO_START_CLOCK_NOT_INITIALIZED;\n\n    VideoParseContext context{};\n\n    while (!boost::this_thread::interruption_requested())\n    {\n        AVPacket packet;\n        if (!m_videoPacketsQueue.pop(packet))\n        {\n            break;\n        }\n\n        auto packetGuard = MakeGuard(&packet, av_packet_unref);\n\n        handleVideoPacket(packet, context);\n    }\n}\n\nbool FFmpegDecoder::handleVideoPacket(\n    const AVPacket& packet,\n    VideoParseContext& context)\n{\n    const int ret = avcodec_send_packet(m_videoCodecContext, &packet);\n    if (ret < 0) {\n        return false;\n    }\n\n    AVFramePtr videoFrame(av_frame_alloc());\n    while (avcodec_receive_frame(m_videoCodecContext, videoFrame.get()) == 0)\n    {\n        if (context.prevVideoFrame)\n        {\n            handleVideoFrame(context.prevVideoFrame, context, videoFrame->best_effort_timestamp);\n            context.prevVideoFrame.reset();\n        }\n\n        if (!handleVideoFrame(videoFrame, context, AV_NOPTS_VALUE))\n        {\n            context.prevVideoFrame = std::move(videoFrame);\n            videoFrame.reset(av_frame_alloc());\n        }\n    }\n\n    return true;\n}\n\nbool FFmpegDecoder::handleVideoFrame(\n    AVFramePtr& videoFrame,\n    VideoParseContext& context,\n    int64_t next_timestamp)\n{\n    enum { MAX_SKIPPED_TILL_REDRAW = 5 };\n    enum { SKIP_LOOP_FILTER_THRESHOLD = 50 };\n    const double MAX_DELAY = 0.2;\n\n    const auto best_effort_timestamp = videoFrame->best_effort_timestamp;\n    const double pts = best_effort_timestamp * av_q2d(m_videoStream->time_base);\n\nrestart:\n\n    boost::posix_time::time_duration td(boost::posix_time::pos_infin);\n    bool inNextFrame = false;\n    bool continueHandlingPrevTime = false;\n\n    for (;;)\n    {\n        boost::unique_lock<boost::mutex> locker(m_isPausedMutex);\n        while (m_isPaused && !m_isVideoSeekingWhilePaused)\n        {\n            m_isPausedCV.wait(locker);\n        }\n\n        const bool isPaused = m_isPaused;\n        inNextFrame = isPaused && m_isVideoSeekingWhilePaused;\n        if (!context.initialized || inNextFrame)\n        {\n            const auto val = (isPaused ? m_pauseTimer : GetHiResTime()) - pts;\n            m_videoStartClock = val;\n            CHANNEL_LOG(ffmpeg_sync) << \"isPaused = \" << isPaused\n                << \" m_videoStartClock = \" << val << \" pts = \" << pts;\n        }\n\n        if (inNextFrame && m_prevTime != AV_NOPTS_VALUE)\n        {\n            if (next_timestamp == AV_NOPTS_VALUE)\n            {\n                return false;\n            }\n            else if (next_timestamp < m_prevTime)\n            {\n                continueHandlingPrevTime = true;\n            }\n            else\n            {\n                m_prevTime = AV_NOPTS_VALUE;\n            }\n        }\n\n        // Skipping frames\n        if (context.initialized && !inNextFrame && !m_videoPacketsQueue.empty())\n        {\n            const double deltaTime = m_videoStartClock + pts - GetHiResTime();\n            if (deltaTime <= 0)\n            {\n                if (deltaTime < -MAX_DELAY)\n                {\n                    InterLockedAdd(m_videoStartClock, MAX_DELAY);\n                }\n\n                ++context.numSkipped;\n                if (context.numSkipped == SKIP_LOOP_FILTER_THRESHOLD)\n                {\n                    if (m_videoCodecContext->skip_loop_filter != AVDISCARD_ALL)\n                    {\n                        // https://trac.kodi.tv/ticket/4943\n                        CHANNEL_LOG(ffmpeg_sync) << \"skip_loop_filter = AVDISCARD_ALL\";\n                        m_videoCodecContext->skip_loop_filter = AVDISCARD_ALL;\n                    }\n                }\n                if ((context.numSkipped % MAX_SKIPPED_TILL_REDRAW) != 0)\n                {\n                    CHANNEL_LOG(ffmpeg_sync) << \"Hard skip frame\";\n                    return true;\n                }\n            }\n            else\n            {\n                if (deltaTime > 0.3 && m_formatContexts.size() == 1)\n                {\n                    locker.unlock();\n                    boost::this_thread::sleep_for(boost::chrono::milliseconds(100));\n                    continue;\n                }\n\n                const auto speed = getSpeedRational();\n                context.numSkipped = 0;\n                td = boost::posix_time::milliseconds(\n                    int(deltaTime * 1000.  * speed.denominator / speed.numerator) + 1);\n            }\n        }\n\n        break;\n    }\n\n    context.initialized = true;\n\n    if (continueHandlingPrevTime)\n    {\n        m_isPausedCV.notify_all();\n        return true;\n    }\n\n    boost::shared_ptr<ImageConversionFunc> imageConversionFunc = m_imageConversionFunc;\n    const bool useAsyncConversion = imageConversionFunc != nullptr && (*imageConversionFunc);\n\n    handleDirect3dData(videoFrame.get(), useAsyncConversion);\n\n    std::future<bool> convert;\n    std::promise<VideoFrame*> videoFramePromise;\n\n    auto promGuard = MakeGuard(&videoFramePromise, [](auto promise) { promise->set_value(nullptr); });\n\n    if (useAsyncConversion)\n    {\n        AVFramePtr input(av_frame_alloc());\n\n        //std::swap(input, videoFrame);\n        const auto res = av_frame_ref(input.get(), videoFrame.get());\n        assert(res == 0);\n        if (res != 0)\n        {\n            CHANNEL_LOG(ffmpeg_sync) << \"av_frame_ref failed with error code: \" << res;\n            return true;\n        }\n\n        auto asyncConversion = GetAsyncConversionFunction(\n            context.tokenGenerator.generate(),\n            std::move(input),\n            videoFramePromise,\n            std::move(imageConversionFunc),\n            m_pixelFormat);\n\n        convert = std::async(std::launch::async, std::move(asyncConversion));\n    }\n\n    {\n        boost::unique_lock<boost::mutex> locker(m_videoFramesMutex);\n\n        if (!m_videoFramesCV.timed_wait(locker, td, [this]\n        {\n            return m_isPaused && !m_isVideoSeekingWhilePaused ||\n                m_videoFramesQueue.canPush();\n        }))\n        {\n            CHANNEL_LOG(ffmpeg_sync) << \"Frame wait abandoned\";\n            return true;\n        }\n    }\n\n    {\n        boost::lock_guard<boost::mutex> locker(m_isPausedMutex);\n        if (m_isPaused && !m_isVideoSeekingWhilePaused)\n        {\n            goto restart;\n        }\n\n        m_isVideoSeekingWhilePaused = false;\n    }\n\n    if (inNextFrame)\n    {\n        m_isPausedCV.notify_all();\n    }\n\n    VideoFrame& current_frame = m_videoFramesQueue.back();\n\n    if (!useAsyncConversion && !frameToImage(current_frame, videoFrame, m_imageCovertContext, m_pixelFormat))\n    {\n        return true;\n    }\n\n    current_frame.m_pts = pts;\n    current_frame.m_duration = best_effort_timestamp;\n\n    if (useAsyncConversion)\n    {\n        promGuard.release();\n        videoFramePromise.set_value(&current_frame);\n        current_frame.m_convert = std::move(convert);\n    }\n\n    {\n        boost::lock_guard<boost::mutex> locker(m_videoFramesMutex);\n        m_videoFramesQueue.pushBack();\n    }\n    m_videoFramesCV.notify_all();\n\n    return true;\n}\n"
  },
  {
    "path": "video/vqueue.h",
    "content": "#pragma once\n\n#include <cassert>\n\n// Video frame struct for RGB24 frame (used by displays)\nclass VQueue\n{\npublic:\n    VQueue() = default;\n    VQueue(const VQueue&) = delete;\n    VQueue& operator=(const VQueue&) = delete;\n\n    void clear()\n    {\n        for (auto& frame : m_frames)\n        {\n            frame.free();\n        }\n\n        // Reset readers\n        m_write_counter = 0;\n        m_read_counter = 0;\n        m_busy = 0;\n    }\n\n    bool canPush() const { return m_busy < QUEUE_SIZE; }\n    VideoFrame& back() { return m_frames[m_write_counter]; }\n    void pushBack()\n    {\n        m_write_counter = (m_write_counter + 1) % QUEUE_SIZE;\n        ++m_busy;\n        assert(m_busy <= VQueue::QUEUE_SIZE);\n    }\n\n    bool canPop() const { return m_busy > 0; }\n    VideoFrame& front() { return m_frames[m_read_counter]; }\n    void popFront()\n    {\n        --m_busy;\n        assert(m_busy >= 0);\n        m_read_counter = (m_read_counter + 1) % QUEUE_SIZE;\n    }\n\nprivate:\n    enum { QUEUE_SIZE = 2 }; // enough for displaying one frame.\n\n    VideoFrame m_frames[QUEUE_SIZE];\n    int m_write_counter = 0;\n    int m_read_counter = 0;\n    int m_busy = 0;\n};\n"
  }
]