diff --git a/.appveyor/afterDeploy.ps1 b/.appveyor/afterDeploy.ps1 new file mode 100644 index 00000000..6fda8b82 --- /dev/null +++ b/.appveyor/afterDeploy.ps1 @@ -0,0 +1,9 @@ +Write-Host "Deployment finished -> do en empty commit on the gh-pages branch to update the page" +cd .. +git clone -q "https://github.com/Vocaluxe/Vocaluxe.git" -b "gh-pages" --single-branch "VocaluxeWeb" +cd VocaluxeWeb +git config --global user.email "noreply@vocaluxe.org" +git config --global user.name "VocaluxeBuildBot" +git commit --allow-empty -m "Trigger page update after a new publish (triggered by $Env:APPVEYOR_REPO_COMMIT_MESSAGE [$Env:APPVEYOR_REPO_COMMIT])" +git push -q "https://$($Env:GitHubKey):x-oauth-basic@github.com/Vocaluxe/Vocaluxe.git" "gh-pages" +cd ..\Vocaluxe \ No newline at end of file diff --git a/.appveyor/prepareDeploy.ps1 b/.appveyor/prepareDeploy.ps1 index 922a6550..e9db2bc9 100644 --- a/.appveyor/prepareDeploy.ps1 +++ b/.appveyor/prepareDeploy.ps1 @@ -7,6 +7,8 @@ else{ Return; } +$Env:IS_BETA_RELEASE = ($Env:APPVEYOR_REPO_TAG_NAME -match "beta") + $getRelaseInfoParams = @{ Uri = "https://api.github.com/repos/Vocaluxe/Vocaluxe/releases/tags/$targetTag"; Method = 'GET'; @@ -23,20 +25,26 @@ catch [System.Net.WebException] # No Release found for this tag $statusCode = [int]$_.Exception.Response.StatusCode $html = $_.Exception.Response.StatusDescription - Write-Host "No Release found for this tag ($html): $($Env:APPVEYOR_REPO_TAG_NAME)" + Write-Host "No Release found for this tag ($html): $targetTag" Return; } -$assetId = ($result.assets | where {$_.name -EQ "Vocaluxe_$($Env:APPVEYOR_REPO_TAG_NAME)_Windows_$($Env:PLATFORM).zip" } | Select-Object -first 1 ).id +$releaseId = $result.id -if(!$assetId){ - # No matching asset found in this release - Write-Host "No matching asset found in this release: Vocaluxe_$($Env:APPVEYOR_REPO_TAG_NAME)_Windows_$($Env:PLATFORM).zip" +if(!$releaseId){ + # No matching release found in this release + Write-Host "No matching release found" + Return; +} + +if($result.body -match $Env:APPVEYOR_REPO_COMMIT){ + # An other build already recreated the release + Write-Host "An other build already recreated the release" Return; } $deleteAssetParams = @{ - Uri = "https://api.github.com/repos/Vocaluxe/Vocaluxe/releases/assets/$assetId"; + Uri = "https://api.github.com/repos/Vocaluxe/Vocaluxe/releases/$releaseId"; Method = 'DELETE'; Headers = @{ Authorization = 'Basic ' + [Convert]::ToBase64String( @@ -45,14 +53,14 @@ $deleteAssetParams = @{ } try{ $result = Invoke-RestMethod @deleteAssetParams - Write-Host "Successfully deleted asset: Vocaluxe_$($Env:APPVEYOR_REPO_TAG_NAME)_Windows_$($Env:PLATFORM).zip" + Write-Host "Successfully deleted release for: $targetTag" } catch [System.Net.WebException] { - # Could not delete asset + # Could not delete release $statusCode = [int]$_.Exception.Response.StatusCode $html = $_.Exception.Response.StatusDescription - Write-Host "Could not delete asset ($html): Vocaluxe_$($Env:APPVEYOR_REPO_TAG_NAME)_Windows_$($Env:PLATFORM).zip" + Write-Host "Could not delete release ($html) for: $targetTag" Return; } \ No newline at end of file diff --git a/Vocaluxe/Linux/Build/PostBuildEvent.sh b/.build/linuxPostBuildEvent.sh old mode 100755 new mode 100644 similarity index 83% rename from Vocaluxe/Linux/Build/PostBuildEvent.sh rename to .build/linuxPostBuildEvent.sh index 92b73c10..fe52ac53 --- a/Vocaluxe/Linux/Build/PostBuildEvent.sh +++ b/.build/linuxPostBuildEvent.sh @@ -4,4 +4,5 @@ cd $PROJECT sed -i -r -e 's/AssemblyInformationalVersion\(".*?"\)/AssemblyInformationalVersion("GITVERSION")/' $PROJECT/Properties/AssemblyInfo.cs sed -i -r -e 's/AssemblyVersion\(".*?"\)/AssemblyVersion("SHORTVERSION")/' $PROJECT/Properties/AssemblyInfo.cs sed -i -r -e 's/AssemblyFileVersion\(".*?"\)/AssemblyFileVersion("SHORTVERSION")/' $PROJECT/Properties/AssemblyInfo.cs +sed -i -r -e 's/AssemblyTitle\(".*?"\)/AssemblyTitle("FULLVERSION")/' $PROJECT/Properties/AssemblyInfo.cs sed -i -e 's/var matchingServerVersion = "";/var matchingServerVersion = "'$(git describe --long)'";/' $PROJECT/../Output/Website/js/main.js diff --git a/.build/linuxPreBuildEvent.sh b/.build/linuxPreBuildEvent.sh new file mode 100644 index 00000000..329c0678 --- /dev/null +++ b/.build/linuxPreBuildEvent.sh @@ -0,0 +1,29 @@ +#!/bin/sh +PROJECT=$1 +cd $PROJECT +arch=$2 +version=$(git describe --long) +shortVersion=${version%%-*} +shortVersionClean=$(echo $shortVersion | sed -e 's/alpha/0/' -e 's/beta/1/' -e 's/rc/2/' -e 's/[[:alpha:]]//g') + +case ${shortVersion##*.} in +alpha*) + releaseType='Alpha' + ;; +beta*) + releaseType='Beta' + ;; +rc*) + releaseType='RC' + ;; +*) + releaseType='Release' + ;; +esac + +versionName=$(grep -oP "\"${shortVersionClean%.*}.\" *: *\"\K([^\"]+)(?=\")" ../.build/versionNames.json) +fullVersionName="Vocaluxe $([ "$versionName" == "" ] && echo "" || echo "'$versionName' ")$shortVersion ($arch) $([ "$releaseType" == "Release" ] && echo "" || echo "$releaseType ")($version)" + +sed -i -e s/GITVERSION/$(git describe --long)/ $PROJECT/Properties/AssemblyInfo.cs +sed -i -e s/SHORTVERSION/"$shortVersionClean"/ $PROJECT/Properties/AssemblyInfo.cs +sed -i -e s/FULLVERSION/"$fullVersionName"/ $PROJECT/Properties/AssemblyInfo.cs \ No newline at end of file diff --git a/.build/versionNames.json b/.build/versionNames.json new file mode 100644 index 00000000..2717f816 --- /dev/null +++ b/.build/versionNames.json @@ -0,0 +1,7 @@ +{ + "0.0.": "Unversioned Build", + "0.1.": "Rising Start", + "0.2.": "Sparkling Sky", + "0.3.": "Shining Heaven", + "0.4.": "Blue Sunrise" +} diff --git a/.build/winPostBuild.ps1 b/.build/winPostBuild.ps1 new file mode 100644 index 00000000..416353fc --- /dev/null +++ b/.build/winPostBuild.ps1 @@ -0,0 +1,23 @@ +param( + [Parameter(Mandatory=$true)] + [String]$ProjectDir +) + +if($Env:GIT_VERSION_TAG) +{ + $version = $Env:GIT_VERSION_TAG; +} +else +{ + $version = git describe --long; +} + +(Get-Content -Encoding UTF8 "$($ProjectDir)..\Output\Website\js\main.js") ` + | Foreach-Object {$_ -replace '(?<=var *matchingServerVersion * = *\")\w*(?=\" *;)', "$version"} ` + | Set-Content -Encoding UTF8 "$($ProjectDir)..\Output\Website\js\main.js" + +(Get-Content -Encoding UTF8 "$($ProjectDir)Properties\AssemblyInfo.cs") ` + | Foreach-Object {$_ -replace '(?<=AssemblyInformationalVersion\(\").*(?=\")', 'GITVERSION'} ` + | Foreach-Object {$_ -replace '(?<=(AssemblyVersion|AssemblyFileVersion)\(\").*(?=\")', 'SHORTVERSION'} ` + | Foreach-Object {$_ -replace '(?<=AssemblyTitle\(\").*(?=\")', 'FULLVERSION'} ` + | Set-Content -Encoding UTF8 "$($ProjectDir)Properties\AssemblyInfo.cs" \ No newline at end of file diff --git a/.build/winPreBuild.ps1 b/.build/winPreBuild.ps1 new file mode 100644 index 00000000..a26a9300 --- /dev/null +++ b/.build/winPreBuild.ps1 @@ -0,0 +1,40 @@ +param( + [Parameter(Mandatory=$true)] + [String]$ProjectDir, + [Parameter(Mandatory=$true)] + [String]$Arch +) + +if($Env:GIT_VERSION_TAG) +{ + $version = $Env:GIT_VERSION_TAG; +} +else +{ + $version = git describe --long; +} + +$shortVersion = $version.Split('-')[0]; + +[System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") +$versionName = (New-Object System.Web.Script.Serialization.JavaScriptSerializer).Deserialize((Get-Content "$($ProjectDir)..\.build\versionNames.json"), ` + [System.Collections.Hashtable])[([regex]"[0-9]+\.[0-9]+\.").Match($shortVersion).Value] + +$releaseType = switch -wildcard ($shortVersion.Split('.')[2]) +{ + "alpha*" {"Alpha"} + "beta*" {"Beta"} + "rc*" {"RC"} + default {"Release"} +}; + +$fullVersionName = "Vocaluxe $(if($versionName) {"'"+$versionName+"' "} else {''})$shortVersion ($Arch) $(if($releaseType -ne "Release") {'$releaseType '} else {''})($version)" + +(Get-Content -Encoding UTF8 "$($ProjectDir)Properties\AssemblyInfo.cs") ` + | Foreach-Object {$_ ` + -replace '(?<=AssemblyInformationalVersion\(").*(?=")', $version ` + -replace '(?<=(AssemblyVersion|AssemblyFileVersion)\(").*(?=")', ` + ($version.Split('-')[0].replace('alpha','0').replace('beta','1').replace('rc','2') -replace "[a-zA-Z]+","")` + -replace '(?<=AssemblyTitle\(").*(?=")', $fullVersionName ` + -replace '(?<=AssemblyCopyright\(".*)[0-9]+(?=")', (Get-Date).Year} ` + | Set-Content -Encoding UTF8 "$($ProjectDir)Properties\AssemblyInfo.cs" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 9de55a61..16254856 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ obj PitchTracker.dll Thumbs.db .transifexrc +.vs tx.exe *.mp4 *.pdb @@ -30,6 +31,7 @@ tx.exe *.user *.VC.db *.VC.opendb +*.dll.config /*.vsp /*.ctl /Output/Config.xml @@ -48,16 +50,16 @@ tx.exe /Output/Songs /Output/Playlists/*.xml /Output/Profiles/*.xml +/Output/Profiles/*.png /Output/PartyModes/*/Code/* /PartyModes/*/*/*.dll /VocaluxeLib/bin /ServerLib/bin/ClientServerLib.dll /Installer/setup-cache -/Installer/setup-SetupFiles -/Installer/vocaluxe-*-setup.exe -/Installer/Vocaluxe*.rar -/Installer/Prerequisites/GStreamer x64/gstreamer-1.0-x86_64-1.4.1.msi -/Installer/Prerequisites/GStreamer x86/gstreamer-1.0-x86-1.4.1.msi +/Installer/Files +/Installer/log.txt +/Installer/setup-cache +/Installer/Setup Files /WebserverInitalConfig/bin /PhoneGap/ /TestResults diff --git a/Installer/Prerequisites/.NET Framework 4.0 Client Profile/dotNetFx40_Client_x86_x64.exe b/Installer/Prerequisites/.NET Framework 4.0 Client Profile/dotNetFx40_Client_x86_x64.exe deleted file mode 100644 index 80ce5d46..00000000 Binary files a/Installer/Prerequisites/.NET Framework 4.0 Client Profile/dotNetFx40_Client_x86_x64.exe and /dev/null differ diff --git a/Installer/Prerequisites/DirectX 9/dxwebsetup.exe b/Installer/Prerequisites/DirectX 9/dxwebsetup.exe deleted file mode 100644 index c15749ed..00000000 Binary files a/Installer/Prerequisites/DirectX 9/dxwebsetup.exe and /dev/null differ diff --git a/Installer/Prerequisites/Visual C++ 2008 SP1 Redistributable/vcredist_x86.exe b/Installer/Prerequisites/Visual C++ 2008 SP1 Redistributable/vcredist_x86.exe deleted file mode 100644 index 05d0a05e..00000000 Binary files a/Installer/Prerequisites/Visual C++ 2008 SP1 Redistributable/vcredist_x86.exe and /dev/null differ diff --git a/Installer/Prerequisites/Visual C++ Redistributable for Visual Studio 2012 x64/vcredist_x64.exe b/Installer/Prerequisites/Visual C++ Redistributable for Visual Studio 2012 x64/vcredist_x64.exe deleted file mode 100644 index 9b5df432..00000000 Binary files a/Installer/Prerequisites/Visual C++ Redistributable for Visual Studio 2012 x64/vcredist_x64.exe and /dev/null differ diff --git a/Installer/Prerequisites/Visual C++ Redistributable for Visual Studio 2012 x86/vcredist_x86.exe b/Installer/Prerequisites/Visual C++ Redistributable for Visual Studio 2012 x86/vcredist_x86.exe deleted file mode 100644 index c247e7e6..00000000 Binary files a/Installer/Prerequisites/Visual C++ Redistributable for Visual Studio 2012 x86/vcredist_x86.exe and /dev/null differ diff --git a/Installer/build.bat b/Installer/build.bat deleted file mode 100644 index f4830f67..00000000 --- a/Installer/build.bat +++ /dev/null @@ -1,14 +0,0 @@ -REM compile x64 -call "%VS110COMNTOOLS%\..\..\VC\vcvarsall.bat" x64 -devenv.com ..\Vocaluxe.sln /Rebuild "InstallerWin|x64" - -REM remove old x64 executables if found and rename -if exist "..\Output\Vocaluxe_x64.exe" del "..\Output\Vocaluxe_x64.exe" -ren "..\Output\Vocaluxe.exe" "Vocaluxe_x64.exe" - -REM compile x86 -call "%VS110COMNTOOLS%\..\..\VC\vcvarsall.bat" x86 -devenv.com ..\Vocaluxe.sln /Rebuild "InstallerWin|x86" - -REM compile installer -AdvancedInstaller.com /rebuild setup.aip \ No newline at end of file diff --git a/Installer/buildinstaller.bat b/Installer/buildinstaller.bat new file mode 100644 index 00000000..ce4e3898 --- /dev/null +++ b/Installer/buildinstaller.bat @@ -0,0 +1,74 @@ +:: Build script for vocaluxe installer (x86 and x64 versions) +:: +:: Requirements +:: - wget.exe: http://gnuwin32.sourceforge.net/packages/wget.htm +:: - unzip.exe: http://gnuwin32.sourceforge.net/packages/unzip.htm +:: - nuget.exe: https://www.nuget.org/downloads +:: - Visual Studio with devenv.exe (should be located in somewhere in Visual Studio folder, e.g. C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE) +:: - AdvancedInstaller + +@ECHO OFF +echo Cloning vocaluxe from github and checkout master +if exist "Files" ( + cd Files + git checkout -q develop >> log.txt + git pull -q >> log.txt + cd ../ +) else ( + git clone -q https://github.com/Vocaluxe/Vocaluxe.git Files > log.txt + cd Files + git checkout -q develop >> log.txt + cd ../ +) +echo - Done +echo. + +echo Download ambient videos and move them to themes folder +wget --append-output=log.txt -q -O videos.zip https://github.com/lukeIam/VocaluxeDependencies/blob/master/zips/themes/vocaluxe.themes.ambient.video.zip?raw=true || goto :error +unzip -q -o -d Files/Output videos.zip || goto :error +del /q videos.zip >> log.txt || goto :error +echo - Done +echo. + +echo Delete lib-folder to prevent packing wrong dlls +del /q Files\Output\libs >> log.txt || goto :error +echo - Done +echo. + +echo Restore dependencies and build x64 +nuget restore Files/Vocaluxe.sln >> log.txt || goto :error +devenv Files/Vocaluxe.sln /Build "InstallerWin|x64" >> log.txt || goto :error +echo - Done +echo. + +echo Build x64 installer +AdvancedInstaller.com /rebuild setup.aip -buildslist x64 >> log.txt || goto :error +echo - Done +echo. + +echo Delete lib-folder to prevent packing wrong dlls +del /q Files\Output\libs >> log.txt || goto :error +echo - Done +echo. + +echo Restore dependencies and build x86 +nuget restore Files/Vocaluxe.sln >> log.txt || goto :error +devenv Files/Vocaluxe.sln /Build "InstallerWin|x86" >> log.txt || goto :error +echo - Done +echo. + +echo Build x86 installer +AdvancedInstaller.com /rebuild setup.aip -buildslist x86 >> log.txt || goto :error +echo - Done +echo. + +echo Everything is done! + +pause +goto :EOF + +:error +echo Failed with error #%errorlevel%. +echo See log.txt for more details. +pause +exit /b %errorlevel% \ No newline at end of file diff --git a/Installer/buildportable.bat b/Installer/buildportable.bat deleted file mode 100644 index 1b7aa978..00000000 --- a/Installer/buildportable.bat +++ /dev/null @@ -1,20 +0,0 @@ -@echo off -SET version=v0.3.0 -SET status=Beta -SET buildnum=0081 -SET buildname=Vocaluxe %version% %status% (%buildnum%).rar - -REM compile x64 -call "%VS110COMNTOOLS%\..\..\VC\vcvarsall.bat" x64 -devenv.com ..\Vocaluxe.sln /Rebuild "ReleaseWin|x64" - -REM remove old x64 executables if found and rename -if exist "..\Output\Vocaluxe_x64.exe" del "..\Output\Vocaluxe_x64.exe" -ren "..\Output\Vocaluxe.exe" "Vocaluxe_x64.exe" - -REM compile x86 -call "%VS110COMNTOOLS%\..\..\VC\vcvarsall.bat" x86 -devenv.com ..\Vocaluxe.sln /Rebuild "ReleaseWin|x86" - -REM package -rar a -r -ep1 -x..\Output\CoverDB.sqlite -x..\Output\HighscoreDB.sqlite -x..\Output\*.log -x..\Output\*.pdb -x..\Output\Config.xml -x..\Output\Vocaluxe.vshost* -x..\Output\Songs -x..\Output\Screenshots -x..\Output\Playlists "%buildname%" "..\Output\*" \ No newline at end of file diff --git a/Installer/setup.aip b/Installer/setup.aip index 90e1b4e3..1309ecc0 100644 --- a/Installer/setup.aip +++ b/Installer/setup.aip @@ -1,645 +1,3793 @@ - + + + + - + + - - - + + + + + - - - - + + - - - + + - + - - + + - + - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + + - - - + + - - - - - - - - + + + + + + + + + + + - - - + @@ -653,27 +3801,46 @@ + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + - - + + - + @@ -683,36 +3850,29 @@ - - + + - - - - + - - - - - - - - + + - - + + + + @@ -722,69 +3882,20 @@ + - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + @@ -794,6 +3905,7 @@ + @@ -803,144 +3915,86 @@ - + + + + + - + + - - - - - - - - - - - + + + - + - - - + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - + + - - + + - + - - - - + + + - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + @@ -951,71 +4005,35 @@ - - - - - - - - - - - - + + + - - - - - - - - - - - - - + - - - - + + - + - - - - - - - - + + + + - - - - - - - - - - - - + + + diff --git a/Output/Languages/Czech.xml b/Output/Languages/Czech.xml index a34fe68f..fe288daf 100644 --- a/Output/Languages/Czech.xml +++ b/Output/Languages/Czech.xml @@ -73,6 +73,8 @@ Celkem Normální Rozšířené + Uvést vše + Uvést nejlepší Vlastní hudba a hudba na pozadí Žádná vlastní hudba Pouze vlastní hudba @@ -183,6 +185,7 @@ Karty Obtížnost hry Režim časomíry + Styl pro nejlepší výsledky Nastavení nahrávání Zařízení Vstup @@ -201,6 +204,7 @@ Zdroj hudby na pozadí Hlasitost ukázky Hlasitost hry + Efekt Karaoke Nastavení tématu Téma Vzhled diff --git a/Output/Languages/French.xml b/Output/Languages/French.xml index fe0c7149..5820b536 100644 --- a/Output/Languages/French.xml +++ b/Output/Languages/French.xml @@ -46,6 +46,7 @@ Niveau 2 Niveau 3 Max + Afficher Caroussel Damier Livre @@ -72,6 +73,8 @@ Total Normal Développé + Tout afficher + Afficher les meilleurs Musique personnelle et Musique de fond Pas de Musique personnelle Seulement la Musique personnelle @@ -79,6 +82,10 @@ Tout Seulement noms et avatars Rien + Remplir + Sauter + Glisser + Zoomer En bas En haut En haut et en bas @@ -178,6 +185,7 @@ Dossiers Difficulté du Jeu Mode du Minuteur + Style meilleur score Options d'Enregistrement Appareil Entrée @@ -196,6 +204,7 @@ Source de la Musique de fond Volume de la Musique de prévisualisation Volume de la Musique du jeu + Effet Karaoké Options du Thème Thème Environnement graphique diff --git a/Output/Languages/Italian.xml b/Output/Languages/Italian.xml index 8fce81fc..57fd6652 100644 --- a/Output/Languages/Italian.xml +++ b/Output/Languages/Italian.xml @@ -46,6 +46,7 @@ Livello 2 Livello 3 Max + Elenco Dreidel Scacchiera Libro @@ -72,6 +73,8 @@ Totale Normale Espanso + Elenco tutti + Elenco migliori Musica personale e musica di sfondo Nessuna musica personale Solo musica personale @@ -79,6 +82,9 @@ Tutto Solo nomi e avatar Niente + Riempi + Salta + Zoom Sotto Sopra Sopra e sotto @@ -196,6 +202,7 @@ Sorgente musica di sfondo Anteprima volume musica Volume musica di gioco + Effetto karaoke Opzioni tema Tema Skin diff --git a/Output/Languages/Spanish.xml b/Output/Languages/Spanish.xml index ed040314..400027a8 100644 --- a/Output/Languages/Spanish.xml +++ b/Output/Languages/Spanish.xml @@ -46,6 +46,7 @@ Nivel 2 Nivel 3 Máx + Listado Dreidel Cuadrícula Libro @@ -72,6 +73,8 @@ Total Normal Expandido + Ver todo + Mejores puntuaciones Canciones del juego y tema Vocaluxe Sin canciones del juego Solo canciones del juego @@ -79,6 +82,10 @@ Todas Solo nombres y avatares Nada + Rellenar + Saltar + Deslizar + Zoom Abajo Arriba Arriba y abajo @@ -89,11 +96,22 @@ cargadas Menú Principal Cantar + Fiesta Opciones Perfiles ¡No se encuentra perfil! + Selección del modo fiesta + Modo fiesta + Descripción + Autor + Versión + No se puede cargar este modo de fiesta ¡No hay micrófonos configurados! ¡Se necesitan %d micrófonos para este modo fiesta! + Audiencia objetiva + No hay equipos + Número de equipos + Número de jugadores Selección de Jugadores Jugador 1 Jugador @@ -107,7 +125,19 @@ Advertencia: ¡No hay perfil asignados al jugador %v! Advertencia: ¡No hay perfiles asignados a los jugadores %v! Selección de Canciones + Cantar + Añadir a lista de reproducción + Cerrar + Seleccionar una canción aleatoriamente + Seleccionar una categoria aleatoriamente + Cantar todas las canciones + Cantar todas las canciones visibles + Abrir lista de reproducción Seleccionar + Cantar una versión corta de canción aleatoria + Cantar versión corta de canción + Nueva lista de reproducción + Opciones de canción Buscar: Sin Idioma Sin Año @@ -155,6 +185,7 @@ Etiquetas Dificultad del Juego Modo del Timer + Estilo de puntuación máxima Opciones de Grabación Dispositivo Entrada @@ -173,6 +204,7 @@ Origen de la Música de Fondo Volumen de la música de la vista previa Volumen de la música del juego + Efecto karaoke Opciones de Estilo Estilo Skin diff --git a/Output/PartyModes/Challenge/Languages/Czech.xml b/Output/PartyModes/Challenge/Languages/Czech.xml index 5dc3a83d..c0fce8eb 100644 --- a/Output/PartyModes/Challenge/Languages/Czech.xml +++ b/Output/PartyModes/Challenge/Languages/Czech.xml @@ -15,6 +15,8 @@ Počet hráčů Počet mikrofonů Počet kol + Počet žolíků + Doplnit žolíky každé kolo Soutěžní režim: Výběr hráče Vybrat náhodně Soutěžní režim: Přehled diff --git a/Output/PartyModes/Challenge/Languages/French.xml b/Output/PartyModes/Challenge/Languages/French.xml index 7ff1b981..27ece675 100644 --- a/Output/PartyModes/Challenge/Languages/French.xml +++ b/Output/PartyModes/Challenge/Languages/French.xml @@ -15,6 +15,8 @@ Nombre de joueurs Nombre de micros Nombre de tours + Nombre de jokers + Remplir de nouveau les jokers à tour Mode Challenge: Choix des joueurs Sélectionner au hasard Mode Challenge: Résumé diff --git a/Output/PartyModes/Challenge/Languages/Spanish.xml b/Output/PartyModes/Challenge/Languages/Spanish.xml index 60b91f04..e2352f20 100644 --- a/Output/PartyModes/Challenge/Languages/Spanish.xml +++ b/Output/PartyModes/Challenge/Languages/Spanish.xml @@ -15,6 +15,8 @@ TODO: Number of players TODO: Number of mics TODO: Number of rounds + Número de comodines + Rellenar comodines cada ronda TODO: Challenge Mode: Choose Player Seleccionar aleatoriamente TODO: Challenge Mode: Overview diff --git a/Output/Profiles/guest3.xml b/Output/Profiles/guest3.xml index ad3c3eb5..f8b196f8 100644 --- a/Output/Profiles/guest3.xml +++ b/Output/Profiles/guest3.xml @@ -2,7 +2,7 @@ Guest 3 TR_CONFIG_EASY - TR_USERROLE_NORMAL + TR_USERROLE_GUEST TR_CONFIG_ON Avatar_m.png \ No newline at end of file diff --git a/Output/Readme.txt b/Output/Readme.txt index 2b12b84a..2cdffb4b 100644 --- a/Output/Readme.txt +++ b/Output/Readme.txt @@ -1,4 +1,4 @@ -Vocaluxe 0.3 README +Vocaluxe 0.4 README ---------------------------- ================================= @@ -23,25 +23,29 @@ Vocaluxe is an entirely new development in C#, inspired by the original UltraSta and the great Ultrastar Deluxe project. Supported Operating Systems / Requirements: -- WinXP, Vista, Windows 7 or Windows 8 with .NET 4.0 +- Windows Vista, Windows 7, Windows 8 or Windows 10 with .NET 4.0 +- Linux (no official support) - 1 GHz CPU, 512 MB RAM, Graphics card with OpenGL 2.1 or DirectX 9.0 support -- Visual C++ Redistributable Packages 2008 and 2012 +- Visual C++ Redistributable Package 2010 ================================= = 2. Release Notes = ================================= -- The program supports 32bit and 64bit (Vocaluxe_x64.exe) operating systems. +- The program supports 32bit and 64bit (appropriate download package) operating systems. -- To add your existing song collection to Vocaluxe, put your songs into the 'Songs' subfolder. +- When using installer, you can find all mentioned folder in 'Documents/Vocaluxe', otherwise + they should be created just next to 'Vocaluxe.exe' + +- To add your existing song collection to Vocaluxe, put your songs into the 'Songs' subfolder. Alternatively, you can add multiple song paths to Vocaluxe by editing your Config.xml: - - C:\Vocaluxe\Songs - D:\EvenMore\Songs + + C:\Vocaluxe\Songs + D:\EvenMore\Songs - To use your highscore database from UltraStar deluxe 1.0.1, UltraStar deluxe CMD Mod or UltraStar deluxe 1.1, simply copy your Ultrastar.db (rename if necessary) into the main @@ -101,6 +105,8 @@ or from the console: load playlist from this path. Example: Vocaluxe.exe -PlaylistFolder D:\MyPlaylists + +-OldTheme yes : Try to load theme that is created for vocaluxe 0.2 or older (or some pre-release version of 0.3). Enter theme editor and save your theme to convert every file to new syntax. This will be removed in a future version. Complete example: @@ -128,14 +134,18 @@ Vocaluxe.exe -ConfigFile MyConfig.xml -ScoreFile C:\Vocaluxe\Highscores\MyHighsc Song screen [F3] to open/close the song search menu [SPACE] to open/close the song menu +[TAB] to switch selection of song menu and playlist (if opened) [CTRL] + [R] to select a random song [CTRL] + [A] to sing all songs +[CTRL] + [S] to sing current song in medley version [CTRL] + [V] to sing all songs from a category [NUM_1]..[NUM_6] to use a Joker for team 1..6 [A]..[Z] to jump to category/song title starting with that letter Name selection screen [1]..[6] to activate player selection. +[P] to activate fast player selection +[+] or [-] to increase/decrease number of player [Cursor] to select a profile. [Enter] to confirm a selection. @@ -145,20 +155,25 @@ Sing screen [T] to change the time format of the timer. [I] to change view of player information. [W] to activate the configured webcam. +[V] to change video aspect ratio + +Score and highscore screen +[LEFT] or [RIGHT] to show (high)scores of another round (if there is more than one) ================================= = 5. Help & Suppport = ================================= -Bug Tracker: http://84.200.73.138/redmine/projects/vocaluxe +Vocaluxe Homepage: https://vocaluxe.org +Bug Tracker: https://github.com/Vocaluxe/Vocaluxe/issues Translations: https://www.transifex.com/projects/p/vocaluxe/ GitHub Wiki: https://github.com/Vocaluxe/Vocaluxe/wiki -Support Forum (German): http://www.ultra-star.de -Song-DataBase (USDB): http://usdb.animux.de/ +Support Forum (German): http://www.ultra-star.de +Song-DataBase (USDB): http://usdb.animux.de/ ================================= = 6. Source Code = ================================= -Source Code (GitHub): https://github.com/Vocaluxe/Vocaluxe -SF.Net Page: http://sourceforge.net/projects/vocaluxe/ \ No newline at end of file +Source Code (GitHub): https://github.com/Vocaluxe/Vocaluxe +SF.Net Page (outdated): http://sourceforge.net/projects/vocaluxe/ diff --git a/PartyModes/PartyModeChallenge/CPartyScreenChallengeNames.cs b/PartyModes/PartyModeChallenge/CPartyScreenChallengeNames.cs index 9b79c0d2..46d354aa 100644 --- a/PartyModes/PartyModeChallenge/CPartyScreenChallengeNames.cs +++ b/PartyModes/PartyModeChallenge/CPartyScreenChallengeNames.cs @@ -37,6 +37,7 @@ namespace VocaluxeLib.PartyModes.Challenge base.Init(); _PartyMode = (CPartyModeChallenge)base._PartyMode; _AllowChangePlayerNum = false; + _Teams = false; } public override void OnShow() diff --git a/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyNames.cs b/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyNames.cs index 4d92fc7d..a95bfc53 100644 --- a/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyNames.cs +++ b/PartyModes/PartyModeChallengeMedley/CPartyScreenChallengeMedleyNames.cs @@ -37,6 +37,7 @@ namespace VocaluxeLib.PartyModes.ChallengeMedley base.Init(); _PartyMode = (CPartyModeChallengeMedley)base._PartyMode; _AllowChangePlayerNum = false; + _Teams = false; } public override void OnShow() diff --git a/PartyModes/PartyModeTicTacToe/CPartyModeTicTacToe.cs b/PartyModes/PartyModeTicTacToe/CPartyModeTicTacToe.cs index 6cf643e5..636e3cfe 100644 --- a/PartyModes/PartyModeTicTacToe/CPartyModeTicTacToe.cs +++ b/PartyModes/PartyModeTicTacToe/CPartyModeTicTacToe.cs @@ -60,7 +60,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe // ReSharper disable ClassNeverInstantiated.Global public sealed class CPartyModeTicTacToe : CPartyMode - // ReSharper restore ClassNeverInstantiated.Global + // ReSharper restore ClassNeverInstantiated.Global { public override int MinMics { @@ -96,7 +96,9 @@ namespace VocaluxeLib.PartyModes.TicTacToe get { return 10; } } - private enum EStage + public readonly EGameMode[] AvailableGameModes = { EGameMode.TR_GAMEMODE_NORMAL, EGameMode.TR_GAMEMODE_SHORTSONG, EGameMode.TR_GAMEMODE_DUET }; + + private enum EStage { Config, Names, @@ -119,7 +121,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe public int CategoryIndex; public int PlaylistID; - public EGameMode GameMode; + public int GameMode; public List Rounds; public List Songs; @@ -160,7 +162,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe SongSource = ESongSource.TR_ALLSONGS, PlaylistID = 0, CategoryIndex = 0, - GameMode = EGameMode.TR_GAMEMODE_NORMAL, + GameMode = 0, Rounds = new List(), Songs = new List(), NumJokerRandom = new int[2], @@ -432,20 +434,20 @@ namespace VocaluxeLib.PartyModes.TicTacToe for (int i = 0; i < CBase.Playlist.GetSongCount(GameData.PlaylistID); i++) { int id = CBase.Playlist.GetSong(GameData.PlaylistID, i).SongID; - if (CBase.Songs.GetSongByID(id).AvailableGameModes.Contains(GameData.GameMode)) + if (CBase.Songs.GetSongByID(id).AvailableGameModes.Contains(AvailableGameModes[GameData.GameMode])) GameData.Songs.Add(id); } break; case ESongSource.TR_ALLSONGS: ReadOnlyCollection avSongs = CBase.Songs.GetSongs(); - GameData.Songs.AddRange(avSongs.Where(song => song.AvailableGameModes.Contains(GameData.GameMode)).Select(song => song.ID)); + GameData.Songs.AddRange(avSongs.Where(song => song.AvailableGameModes.Contains(AvailableGameModes[GameData.GameMode])).Select(song => song.ID)); break; case ESongSource.TR_CATEGORY: CBase.Songs.SetCategory(GameData.CategoryIndex); avSongs = CBase.Songs.GetVisibleSongs(); - GameData.Songs.AddRange(avSongs.Where(song => song.AvailableGameModes.Contains(GameData.GameMode)).Select(song => song.ID)); + GameData.Songs.AddRange(avSongs.Where(song => song.AvailableGameModes.Contains(AvailableGameModes[GameData.GameMode])).Select(song => song.ID)); CBase.Songs.SetCategory(-1); break; @@ -493,7 +495,7 @@ namespace VocaluxeLib.PartyModes.TicTacToe if (isDuet) players[1].VoiceNr = 1; - CBase.Game.AddSong(round.SongID, GameData.GameMode); + CBase.Game.AddSong(round.SongID, AvailableGameModes[GameData.GameMode]); } private void _SetNumJokers() diff --git a/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeConfig.cs b/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeConfig.cs index c75cd880..feeda81b 100644 --- a/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeConfig.cs +++ b/PartyModes/PartyModeTicTacToe/CPartyScreenTicTacToeConfig.cs @@ -160,8 +160,8 @@ namespace VocaluxeLib.PartyModes.TicTacToe _SelectSlides[_SelectSlideGameMode].Visible = true; _SelectSlides[_SelectSlideGameMode].Clear(); - _SelectSlides[_SelectSlideGameMode].SetValues((int)_PartyMode.GameData.GameMode); - _SelectSlides[_SelectSlideGameMode].RemoveValue(EGameMode.TR_GAMEMODE_MEDLEY.ToString()); + _SelectSlides[_SelectSlideGameMode].AddValues(_PartyMode.AvailableGameModes.Select(gm => gm.ToString())); + _SelectSlides[_SelectSlideGameMode].Selection = _PartyMode.GameData.GameMode; } private void _UpdateSlides() @@ -171,9 +171,9 @@ namespace VocaluxeLib.PartyModes.TicTacToe _PartyMode.GameData.SongSource = (ESongSource)_SelectSlides[_SelectSlideSongSource].Selection; _PartyMode.GameData.PlaylistID = _SelectSlides[_SelectSlidePlaylist].Selection; _PartyMode.GameData.CategoryIndex = _SelectSlides[_SelectSlideCategory].Selection; - _PartyMode.GameData.GameMode = (EGameMode)_SelectSlides[_SelectSlideGameMode].Selection; + _PartyMode.GameData.GameMode = _SelectSlides[_SelectSlideGameMode].Selection; - EGameMode gm = _PartyMode.GameData.GameMode; + EGameMode gm = _PartyMode.AvailableGameModes[_PartyMode.GameData.GameMode]; if (_PartyMode.GameData.SongSource == ESongSource.TR_PLAYLIST) { diff --git a/README.md b/README.md index 9007121b..36330d98 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,11 @@ -![Vocaluxe Logo](https://raw.githubusercontent.com/Vocaluxe/Vocaluxe/develop/Output/Graphics/Logo.png) +![Vocaluxe Logo](https://raw.githubusercontent.com/Vocaluxe/Vocaluxe/develop/Output/Graphics/Logo.png) + +[![Build status](https://ci.appveyor.com/api/projects/status/y9ylgebv14i7usxx/branch/develop?svg=true)](https://ci.appveyor.com/project/VocaluxeBuildBot/vocaluxe/branch/develop) +[![Nightly build](https://img.shields.io/badge/nightly%20build-latest-blue.svg)](https://vocaluxe.org/#download) +[![Latest stable release](https://img.shields.io/github/release/vocaluxe/Vocaluxe.svg?label=stable%20release)](https://vocaluxe.org/#download) +[![Known bugs](https://img.shields.io/github/issues-raw/vocaluxe/vocaluxe/bug.svg?label=known%20bugs)](https://github.com/Vocaluxe/Vocaluxe/labels/bug) +[![Feature requests](https://img.shields.io/github/issues-raw/vocaluxe/vocaluxe/feature%20request.svg?label=feature%20requests&colorB=007ec6)](https://github.com/Vocaluxe/Vocaluxe/labels/feature%20request) +[![License](https://img.shields.io/badge/licence-GPLv3-blue.svg)](https://github.com/Vocaluxe/Vocaluxe/blob/develop/LICENSE.txt) [1. About](#1-about) [2. Download](#2-download) @@ -12,17 +19,15 @@ It features mouse, keyboard, gamepad and Wiimote navigation, a multi-language in Vocaluxe offers diversified party modes and can optionally be controlled via a browser (desktop and mobile supported). Supported Operating Systems / Requirements: -- WinXP, Vista, Windows 7, Windows 8, Windows 8.1 and Windows 10 with .NET 4.0 -- Linux (tested on Arch Linux) +- Windows Vista, Windows 7, Windows 8, Windows 8.1 and Windows 10 with .NET 4.0 +- *Linux* (no official support) - 1 GHz CPU, 512 MB RAM, Graphics card with OpenGL 2.1 or DirectX 9.0 support +- Visual C++ Redistributable Package 2010 ## 2. Download You can download precompiled Windows binaries at here: -http://vocaluxe.sourceforge.net/index.php?p=download - -Nightly builds are available here: -https://github.com/Vocaluxe/Vocaluxe/releases +https://vocaluxe.org/#download ## 3. Contributing You want to fix a bug or add a cool new feature to Vocaluxe? Awesome! @@ -43,6 +48,7 @@ You have a problem or a question implementing your change? Just [open an issue](https://github.com/Vocaluxe/Vocaluxe/issues/new) or mention `@Vocaluxe` in a comment on GitHub. ## 4. Help & Support +Vocaluxe Homepage: https://vocaluxe.org/ GitHub Wiki: https://github.com/Vocaluxe/Vocaluxe/wiki GitHub Issues Tracker: https://github.com/Vocaluxe/Vocaluxe/issues Translations: https://www.transifex.com/projects/p/vocaluxe/ diff --git a/Vocaluxe/Base/CConfig.cs b/Vocaluxe/Base/CConfig.cs index 7d12b96c..7db2f250 100644 --- a/Vocaluxe/Base/CConfig.cs +++ b/Vocaluxe/Base/CConfig.cs @@ -193,11 +193,11 @@ namespace Vocaluxe.Base //Folders public static readonly List SongFolders = new List { -#if WIN +#if INSTALLER + Path.Combine(CSettings.DataFolder, CSettings.FolderNameSongs), + CSettings.FolderNameSongs +#elif WIN CSettings.FolderNameSongs -#elif INSTALLER - CSettings.FolderNameSongs, - Path.Combine(CSettings.DataFolder, CSettings.FolderNameSongs) #elif LINUX Path.Combine(CSettings.DataFolder, CSettings.FolderNameSongs) #endif @@ -208,11 +208,11 @@ namespace Vocaluxe.Base /// public static readonly List ProfileFolders = new List { -#if WIN +#if INSTALLER + Path.Combine(CSettings.DataFolder, CSettings.FolderNameProfiles), + CSettings.FolderNameProfiles +#elif WIN CSettings.FolderNameProfiles -#elif INSTALLER - CSettings.FolderNameProfiles, - Path.Combine(CSettings.DataFolder, CSettings.FolderNameProfiles) #elif LINUX Path.Combine(CSettings.DataFolder, CSettings.FolderNameProfiles) #endif diff --git a/Vocaluxe/Base/CSettings.cs b/Vocaluxe/Base/CSettings.cs index 05c52e2c..917e75bb 100644 --- a/Vocaluxe/Base/CSettings.cs +++ b/Vocaluxe/Base/CSettings.cs @@ -20,8 +20,10 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using System.Text; using System.Windows.Forms; using VocaluxeLib; +using VocaluxeLib.Xml; namespace Vocaluxe.Base { @@ -35,6 +37,8 @@ namespace Vocaluxe.Base // ReSharper restore UnusedMember.Global } + + /// /// This class contains settings for the program /// These are not editable, everything that can be changed by the user is in CConfig @@ -52,26 +56,7 @@ namespace Vocaluxe.Base //TODO: This should not be here as it can change //State of the program public static EProgramState ProgramState = EProgramState.Start; - - //Adjusting of programName and version now in the assembly config. - private static readonly Dictionary _CodeNames = new Dictionary() - { - {"0.3.", "Shining Heaven"}, - {"0.4.", "Blue Sunrise"} - }; - - private static string _ProgramCodeName - { - get - { - var versionParts = Application.ProductVersion.Split('.'); - string name; - _CodeNames.TryGetValue($"{versionParts[0]}.{versionParts[1]}.", out name); - if (name != null) - return name; - return "Unnamed Version"; - } - } + public static ERevision VersionRevision { @@ -208,6 +193,7 @@ namespace Vocaluxe.Base { get { return _Assembly.Name; } } + private static string _Version { get @@ -215,39 +201,10 @@ namespace Vocaluxe.Base return Application.ProductVersion.Split('-').First(); } } - - private static string _GetVersionText() - { - string version = _Version + " (" + _Arch + ")"; - - string gitversion = Application.ProductVersion; - - if (VersionRevision != ERevision.Release || gitversion.Split('-')[1] != "0") - { - version += " " + _GetVersionStatus() + String.Format(" ({0})", gitversion); - } - - return version; - } - + public static string GetFullVersionText() { - string version = ProgramName; - - if (_ProgramCodeName != "") - version += " \"" + _ProgramCodeName + "\""; - - return version + " " + _GetVersionText(); - } - - private static string _GetVersionStatus() - { - string result = ""; - - if (VersionRevision != ERevision.Release) - result = Enum.GetName(typeof(ERevision), VersionRevision); - - return result; + return ((AssemblyTitleAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false).First()).Title; } public static float GetRenderAspect() diff --git a/Vocaluxe/Base/CSongCategorizer.cs b/Vocaluxe/Base/CSongCategorizer.cs index ab7fb777..05a9dba4 100644 --- a/Vocaluxe/Base/CSongCategorizer.cs +++ b/Vocaluxe/Base/CSongCategorizer.cs @@ -126,10 +126,10 @@ namespace Vocaluxe.Base string noCategoryName; switch (CSongs.Sorter.SongSorting) { + case ESongSorting.TR_CONFIG_FOLDER: case ESongSorting.TR_CONFIG_NONE: noCategoryName = CLanguage.Translate("TR_SCREENSONG_ALLSONGS"); break; - case ESongSorting.TR_CONFIG_FOLDER: case ESongSorting.TR_CONFIG_ARTIST: case ESongSorting.TR_CONFIG_ARTIST_LETTER: case ESongSorting.TR_CONFIG_TITLE_LETTER: diff --git a/Vocaluxe/CProgrammHelper.cs b/Vocaluxe/CProgrammHelper.cs index d25b138e..7a3dd995 100644 --- a/Vocaluxe/CProgrammHelper.cs +++ b/Vocaluxe/CProgrammHelper.cs @@ -116,13 +116,20 @@ namespace Vocaluxe public static bool CheckRequirements() { #if WIN - if (!_IsVC2012Installed()) + if (!_IsVC2010Installed()) + { + CLog.LogError( + "VC++ 2010 Redistributables are missing. Please install them first. \r\nDownload(x86): https://www.microsoft.com/de-de/download/details.aspx?id=5555 \r\nDownload(x64): https://www.microsoft.com/de-de/download/details.aspx?id=14632", + true, true); + return false; + } + /*if (!_IsVC2012Installed()) { CLog.LogError( "VC++ 2012 Redistributables are missing. Please install them first.\r\nDownload: http://www.microsoft.com/de-de/download/details.aspx?id=30679", true, true); return false; - } + }*/ /* bool vc2008Installed = _IsVC2008Installed(); if (!vc2008Installed) diff --git a/Vocaluxe/Doc/Roadmap.txt b/Vocaluxe/Doc/Roadmap.txt index 306a3655..ac17e32f 100644 --- a/Vocaluxe/Doc/Roadmap.txt +++ b/Vocaluxe/Doc/Roadmap.txt @@ -88,18 +88,24 @@ - Spectrum Analyzer (Record Screen and Player Selection Screen) - WiiMote Support - + v0.3.0 Shining Heaven (reached: ??.0?.2013): + + v0.3.0 Shining Heaven (release skipped): - Party Mode Support - Party Mode: Challenge Mode (with more than 2 player at once) - Party Mode: Challenge Medley Mode - Party Mode: Tic, Tac, Toe - GStreamer Audio Support + - Smartphone control (webserver) + - Dynamic cover generation + - New Song View: List - + v0.4.0 (reached: ??.??.201?): + + v0.4.0 Blue Sunrise (reached: ??.??.201?): + - A lot of restructered and rewritten lines of code + - Some minor and bigger improvements and additions + - Updated audio and video libs + - New infrastructure: CI with nightly builds, new homepage, updated installer ----------------- just some ideas: - - Installer - More Song List Views - Tile Board: Show title and artist under each tile - OnScreen Keyboard? @@ -121,4 +127,4 @@ some feature wishes: - Party Modes: * add sing modes: hide notes, hide lyrics, ... - * add a party mode where you can assign song categories and/or playlists to the profiles \ No newline at end of file + * add a party mode where you can assign song categories and/or playlists to the profiles diff --git a/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudioStream.cs b/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudioStream.cs index 09248e60..0808b506 100644 --- a/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudioStream.cs +++ b/Vocaluxe/Lib/Sound/Playback/GstreamerSharp/CGstreamerSharpAudioStream.cs @@ -235,6 +235,11 @@ namespace Vocaluxe.Lib.Sound.Playback.GstreamerSharp element = _Element; _Element = null; //Now everything "seems" closed } + + // Should not be needed but we had an error report (#226) - so we double check here to prevent a crash + if (element == null) + return; + if (element.TargetState == State.Playing) element.SetState(State.Paused); //Stop output if (_CloseStreamListener != null) diff --git a/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs b/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs index 91d4e4e1..6af5d259 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CAcinerella.cs @@ -58,7 +58,22 @@ namespace Vocaluxe.Lib.Video.Acinerella [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct SACFileInfo { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] + public readonly string title; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] + public readonly string author; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] + public readonly string copyright; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] + public readonly string comment; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 512)] + public readonly string album; + public readonly int year; + public readonly int track; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public readonly string genre; public readonly Int64 Duration; + public readonly int Bitrate; } // TAc_instance represents an Acinerella instance. Each instance can open and @@ -105,14 +120,17 @@ namespace Vocaluxe.Lib.Video.Acinerella } // Contains information about an Acinerella stream. - [StructLayout(LayoutKind.Sequential)] + [StructLayout(LayoutKind.Explicit)] public struct SACStreamInfo { //Contains the type of the stream. + [FieldOffset(0)] public readonly EACStreamType StreamType; //Additional info about the stream + [FieldOffset(8)] public SACAudioStreamInfo AudioInfo; + [FieldOffset(8)] public SACVideoStreamInfo VideoInfo; } @@ -128,7 +146,7 @@ namespace Vocaluxe.Lib.Video.Acinerella //The timecode of the currently decoded picture in seconds. public readonly double Timecode; - public readonly double VideoClock; + //public readonly double VideoClock; //Contains information about the stream the decoder is attached to. public SACStreamInfo StreamInfo; @@ -219,14 +237,14 @@ namespace Vocaluxe.Lib.Video.Acinerella // Initializes an Acinerella instance. //function ac_init(): PAc_instance; cdecl; external ac_dll; - [DllImport(_AcDll, EntryPoint = "ac_init", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern IntPtr _ac_init(); + [DllImport(_AcDll, EntryPoint = "ac_init_of", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] + private static extern IntPtr _ac_init(EACOutputFormat outputFormat); public static IntPtr AcInit() { lock (_Lock) { - return _ac_init(); + return _ac_init(EACOutputFormat.ACOutputRGBA32); } } @@ -243,52 +261,7 @@ namespace Vocaluxe.Lib.Video.Acinerella } } - // Opens a media file. - // @param(inst specifies the Acinerella Instance the stream should be opened for) - // @param(sender specifies a pointer that is sent to all callback functions to - // allow you to do object orientated programming. May be NULL.) - // @param(open_proc specifies the callback function that is called, when the - // media file is opened. May be NULL.) - // @param(close_proc specifies the callback function that is called when the media - // file is closed. May be NULL.) - /*function ac_open( - inst: PAc_instance; - sender: Pointer; - open_proc: TAc_openclose_callback; - read_proc: TAc_read_callback; - seek_proc: TAc_seek_callback; - close_proc: TAc_openclose_callback; - proberesult: PAc_proberesult): integer; cdecl; external ac_dll; - */ - /* - [DllImport(AcDll, EntryPoint = "ac_open", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern Int32 _ac_open( - IntPtr PAc_instance, - IntPtr sender, - TAc_openclose_callback open_proc, - TAc_read_callback read_proc, - TAc_seek_callback seek_proc, - TAc_openclose_callback close_proc, - IntPtr proberesult - ); - - public static Int32 ac_open( - IntPtr PAc_instance, - IntPtr sender, - TAc_openclose_callback open_proc, - TAc_read_callback read_proc, - TAc_seek_callback seek_proc, - TAc_openclose_callback close_proc, - IntPtr proberesult - ) - { - lock (_GetLockToken(pAcDecoder)) - { - return _ac_open(PAc_instance, sender, open_proc, read_proc, seek_proc, close_proc, proberesult); - } - }*/ - - [DllImport(_AcDll, EntryPoint = "ac_open", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] + [DllImport(_AcDll, EntryPoint = "ac_open_file", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] private static extern Int32 _ac_open2(IntPtr pAcInstance, string filename); // ReSharper disable UnusedMethodReturnValue.Global @@ -337,28 +310,55 @@ namespace Vocaluxe.Lib.Video.Acinerella [DllImport(_AcDll, EntryPoint = "ac_free_package", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] public static extern void ac_free_package(IntPtr pAcPackage); - [DllImport(_AcDll, EntryPoint = "ac_create_video_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern IntPtr _ac_create_video_decoder(IntPtr pAcInstance); + [DllImport(_AcDll, EntryPoint = "ac_create_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] + private static extern IntPtr _ac_create_decoder(IntPtr pAcInstance, int i); public static IntPtr AcCreateVideoDecoder(IntPtr pAcInstance) { lock (_GetLockToken(pAcInstance)) { - return _ac_create_video_decoder(pAcInstance); + var firstVideoStreamId = _GetFirstStreamByType(pAcInstance, EACStreamType.ACStreamTypeVideo); + + if (firstVideoStreamId < 0) + { + throw new ArgumentException("The instace does not contain a video stream."); + } + + return _ac_create_decoder(pAcInstance, firstVideoStreamId); } } - - [DllImport(_AcDll, EntryPoint = "ac_create_audio_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] - private static extern IntPtr _ac_create_audio_decoder(IntPtr pAcInstance); - + public static IntPtr AcCreateAudioDecoder(IntPtr pAcInstance) { lock (_GetLockToken(pAcInstance)) { - return _ac_create_audio_decoder(pAcInstance); + var firstAudioStreamId = _GetFirstStreamByType(pAcInstance, EACStreamType.ACStreamTypeAudio); + + if (firstAudioStreamId < 0) + { + throw new ArgumentException("The instace does not contain a audio stream."); + } + return _ac_create_decoder(pAcInstance, firstAudioStreamId); } } + private static int _GetFirstStreamByType(IntPtr pAcInstance, EACStreamType type) + { + var instance = (SACInstance)Marshal.PtrToStructure(pAcInstance, typeof(SACInstance)); + + int currentStream = 0; + SACStreamInfo currentStreamInfo; + + while (currentStream < instance.StreamCount) + { + AcGetStreamInfo(pAcInstance, currentStream, out currentStreamInfo); + if (currentStreamInfo.StreamType == type) + return currentStream; + currentStream++; + } + return -1; + } + // Frees an created decoder. //procedure ac_free_decoder(pDecoder: PAc_decoder); cdecl; external ac_dll; [DllImport(_AcDll, EntryPoint = "ac_free_decoder", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)] diff --git a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs index a11c1871..38275210 100644 --- a/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs +++ b/Vocaluxe/Lib/Video/Acinerella/CDecoderThread.cs @@ -447,6 +447,7 @@ namespace Vocaluxe.Lib.Video.Acinerella { _Free(); Stop(); + return; } while (!_Terminated) diff --git a/Vocaluxe/Lib/Video/Acinerella/acinerella.c b/Vocaluxe/Lib/Video/Acinerella/acinerella.c index ade729d3..a61fd875 100644 --- a/Vocaluxe/Lib/Video/Acinerella/acinerella.c +++ b/Vocaluxe/Lib/Video/Acinerella/acinerella.c @@ -17,73 +17,111 @@ #include #include -#include "acinerella.h" +#include + #include #include #include #include +#include "libavutil/imgutils.h" #include #include -#include -#define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 -#define AUDIO_BUFFER_BASE_SIZE AVCODEC_MAX_AUDIO_FRAME_SIZE +#include "acinerella.h" -#define CODEC_TYPE_VIDEO AVMEDIA_TYPE_VIDEO -#define CODEC_TYPE_AUDIO AVMEDIA_TYPE_AUDIO +#define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) +#define MAX(X, Y) (((X) > (Y)) ? (X) : (Y)) +#define AC_BUFSIZE 1024 * 64 +#define PROBE_BUF_MIN 1024 +#define PROBE_BUF_MAX (1 << 20) -//This struct represents one Acinerella video object. -//It contains data needed by FFMpeg. - -#define AC_BUFSIZE 1024*64 +#define ERR(E) \ + { \ + if (!(E)) { \ + goto error; \ + } \ + } +#define AV_ERR(E) \ + { \ + if ((E) < 0) { \ + goto error; \ + } \ + } struct _ac_data { - ac_instance instance; - AVFormatContext *pFormatCtx; - void* buffer; + ac_instance instance; + + AVFormatContext *pFormatCtx; + AVIOContext *pIo; + + void *sender; + ac_openclose_callback open_proc; + ac_read_callback read_proc; + ac_seek_callback seek_proc; + ac_openclose_callback close_proc; + + uint8_t *buffer; + uint8_t *probe_buffer; + size_t probe_buffer_size; + size_t probe_buffer_offs; }; typedef struct _ac_data ac_data; -typedef ac_data* lp_ac_data; +typedef ac_data *lp_ac_data; struct _ac_decoder_data { - ac_decoder decoder; + ac_decoder decoder; + int sought; + double last_timecode; }; typedef struct _ac_decoder_data ac_decoder_data; -typedef ac_decoder_data* lp_ac_decoder_data; +typedef ac_decoder_data *lp_ac_decoder_data; struct _ac_video_decoder { - ac_decoder decoder; - AVCodec *pCodec; - AVCodecContext *pCodecCtx; - AVFrame *pFrame; - AVFrame *pFrameRGB; - struct SwsContext *pSwsCtx; + ac_decoder decoder; + int sought; + double last_timecode; + AVCodec *pCodec; + AVCodecContext *pCodecCtx; + AVFrame *pFrame; + AVFrame *pFrameRGB; + struct SwsContext *pSwsCtx; }; typedef struct _ac_video_decoder ac_video_decoder; -typedef ac_video_decoder* lp_ac_video_decoder; +typedef ac_video_decoder *lp_ac_video_decoder; struct _ac_audio_decoder { - ac_decoder decoder; - int max_buffer_size; - AVCodec *pCodec; - AVCodecContext *pCodecCtx; + ac_decoder decoder; + int sought; + double last_timecode; + AVCodec *pCodec; + AVCodecContext *pCodecCtx; + AVFrame *pFrame; + SwrContext *pSwrCtx; + size_t own_buffer_size; }; typedef struct _ac_audio_decoder ac_audio_decoder; -typedef ac_audio_decoder* lp_ac_audio_decoder; +typedef ac_audio_decoder *lp_ac_audio_decoder; struct _ac_package_data { - ac_package package; - AVPacket ffpackage; - int pts; + ac_package package; + AVPacket *pPack; + int pts; }; typedef struct _ac_package_data ac_package_data; -typedef ac_package_data* lp_ac_package_data; +typedef ac_package_data *lp_ac_package_data; + +// +//--- Forward declarations --- +// + +void ac_free_video_decoder(lp_ac_video_decoder pDecoder); +void ac_free_audio_decoder(lp_ac_audio_decoder pDecoder); // //--- Initialization and Stream opening--- @@ -91,702 +129,1035 @@ typedef ac_package_data* lp_ac_package_data; void init_info(lp_ac_file_info info) { - info->duration = -1; + info->title[0] = 0; + info->author[0] = 0; + info->copyright[0] = 0; + info->comment[0] = 0; + info->album[0] = 0; + info->year = -1; + info->track = -1; + info->genre[0] = 0; + info->duration = -1; + info->bitrate = -1; } int av_initialized = 0; void ac_init_ffmpeg() { - if(!av_initialized) - { - avcodec_register_all(); - av_register_all(); - av_initialized = 1; - } + if (!av_initialized) { + avcodec_register_all(); + av_register_all(); + + av_initialized = 1; + } } -lp_ac_instance CALL_CONVT ac_init(void) { - ac_init_ffmpeg(); - - //Allocate a new instance of the videoplayer data and return it - lp_ac_data ptmp; - ptmp = (lp_ac_data)av_malloc(sizeof(ac_data)); - - //Initialize the created structure - memset(ptmp, 0, sizeof(ac_data)); - - ptmp->instance.opened = 0; - ptmp->instance.stream_count = 0; - ptmp->instance.output_format = AC_OUTPUT_RGBA32; - init_info(&(ptmp->instance.info)); - return (lp_ac_instance)ptmp; +lp_ac_instance CALL_CONVT ac_init(void) +{ + ac_init_ffmpeg(); + + // Allocate a new instance of the videoplayer data and return it + lp_ac_data ptmp; + ptmp = (lp_ac_data)av_malloc(sizeof(ac_data)); + + // Initialize the created structure + memset(ptmp, 0, sizeof(ac_data)); + + ptmp->instance.opened = 0; + ptmp->instance.stream_count = 0; + ptmp->instance.output_format = AC_OUTPUT_BGR24; + init_info(&(ptmp->instance.info)); + return (lp_ac_instance)ptmp; } -void CALL_CONVT ac_free(lp_ac_instance pacInstance) { - //Close the decoder. If it is already closed, this won't be a problem as ac_close checks the streams state - ac_close(pacInstance); - - if (pacInstance != NULL) { - av_free((lp_ac_data)pacInstance); - } +lp_ac_instance CALL_CONVT ac_init_of(ac_output_format outputFormat) +{ + ac_init_ffmpeg(); + + // Allocate a new instance of the videoplayer data and return it + lp_ac_data ptmp; + ptmp = (lp_ac_data)av_malloc(sizeof(ac_data)); + + // Initialize the created structure + memset(ptmp, 0, sizeof(ac_data)); + + ptmp->instance.opened = 0; + ptmp->instance.stream_count = 0; + ptmp->instance.output_format = outputFormat; + init_info(&(ptmp->instance.info)); + return (lp_ac_instance)ptmp; } -int CALL_CONVT ac_open(lp_ac_instance pacInstance, const char* filename) -{ - pacInstance->opened = 0; - - /* open input file, and allocate format context */ - int ret = 0; - if ((ret = avformat_open_input(&((lp_ac_data)pacInstance)->pFormatCtx, filename, NULL, NULL)) < 0) - { - return ret; - } - - /* retrieve stream information */ - if ((ret = avformat_find_stream_info(((lp_ac_data)pacInstance)->pFormatCtx, NULL)) < 0) - { - return ret; - } - else - pacInstance->info.duration = ((lp_ac_data)pacInstance)->pFormatCtx->duration * 1000 / AV_TIME_BASE; - - //Set some information in the instance variable - pacInstance->stream_count = ((lp_ac_data)pacInstance)->pFormatCtx->nb_streams; - pacInstance->opened = pacInstance->stream_count > 0; - - return 0; +void CALL_CONVT ac_free(lp_ac_instance pacInstance) +{ + if (pacInstance) { + // Close the decoder. If it is already closed, this won't be a problem + // as + // ac_close checks the streams state + ac_close(pacInstance); + av_free((lp_ac_data)pacInstance); + } } -void CALL_CONVT ac_close(lp_ac_instance pacInstance) { - if (pacInstance->opened) { - //Close the opened file - avformat_close_input(&(((lp_ac_data)(pacInstance))->pFormatCtx)); - pacInstance->opened = 0; +static int io_read(void *opaque, uint8_t *buf, int buf_size) +{ + lp_ac_data self = ((lp_ac_data)opaque); - //If the seek proc has not been specified, the input buffer is not automatically - //freed, as ffmpeg didn't get the original pointer to the buffer - if (((lp_ac_data)(pacInstance))->buffer) { - av_free(((lp_ac_data)(pacInstance))->buffer); + // If there is still memory in the probe buffer, consume this memory first + if (self->probe_buffer && + self->probe_buffer_offs < self->probe_buffer_size) { + // Copy as many bytes as possible from the probe buffer + size_t cnt = + MIN(buf_size, self->probe_buffer_size - self->probe_buffer_offs); + memcpy(buf, self->probe_buffer + self->probe_buffer_offs, cnt); + + // Advance the read/write pointers + self->probe_buffer_offs += cnt; + buf += cnt; + buf_size -= (int)cnt; + + // Free the probe buffer once all bytes have been read + if (self->probe_buffer_offs == self->probe_buffer_size) { + av_free(self->probe_buffer); + self->probe_buffer = NULL; + self->probe_buffer_size = 0; + self->probe_buffer_offs = 0; + } } - } + // Try to read the memory from the probe buffer + if (self->read_proc != NULL) { + return self->read_proc(self->sender, buf, buf_size); + } + + return -1; } -void CALL_CONVT ac_get_stream_info(lp_ac_instance pacInstance, int nb, lp_ac_stream_info info) { - if (!(pacInstance->opened)) { - return; - } - - switch (((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->codec_type) { - case CODEC_TYPE_VIDEO: - //Set stream type to "VIDEO" - info->stream_type = AC_STREAM_TYPE_VIDEO; - - //Store more information about the video stream - info->video_info.frame_width = - ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->width; - info->video_info.frame_height = - ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->height; - - double pixel_aspect_num = ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->sample_aspect_ratio.num; - double pixel_aspect_den = ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->sample_aspect_ratio.den; - - //Sometime "pixel aspect" may be zero or have other invalid values. Correct this. - if (pixel_aspect_num <= 0.0 || pixel_aspect_den <= 0.0) - info->video_info.pixel_aspect = 1.0; - else - info->video_info.pixel_aspect = pixel_aspect_num / pixel_aspect_den; - - info->video_info.frames_per_second = - (double)((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->r_frame_rate.num / - (double)((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->r_frame_rate.den; - break; - case CODEC_TYPE_AUDIO: - //Set stream type to "AUDIO" - info->stream_type = AC_STREAM_TYPE_AUDIO; - - //Store more information about the video stream - info->audio_info.samples_per_second = - ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->sample_rate; - info->audio_info.channel_count = 2; - //((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec->channels; - - // Set bit depth (its always 16Bit because of the conversion! - info->audio_info.bit_depth = 16; - - break; - default: - info->stream_type = AC_STREAM_TYPE_UNKNOWN; - } +static int64_t io_seek(void *opaque, int64_t pos, int whence) +{ + lp_ac_data self = ((lp_ac_data)opaque); + if (self->seek_proc != NULL) { + if ((whence >= 0) && (whence <= 2)) { + return self->seek_proc(self->sender, pos, whence); + } + } + return -1; +} + +lp_ac_proberesult CALL_CONVT ac_probe_input_buffer(uint8_t *buf, int bufsize, + char *filename, + int *score_max) +{ + AVProbeData pd; + AVInputFormat *fmt = NULL; + + // Initialize FFMpeg libraries + ac_init_ffmpeg(); + + // Set the filename and mime_type + pd.mime_type = ""; + pd.filename = ""; + if (filename) { + pd.filename = filename; + } + + // The given buffer has to be copied to a new one, which is aligned and + // padded + uint8_t *aligned_buf = av_malloc(bufsize + AVPROBE_PADDING_SIZE); + memset(aligned_buf, 0, bufsize + AVPROBE_PADDING_SIZE); + memcpy(aligned_buf, buf, bufsize); + + // Set the probe data buffer + pd.buf = aligned_buf; + pd.buf_size = bufsize; + + // Test it + int score_ret; + fmt = av_probe_input_format3(&pd, 1, &score_ret); + if (score_ret > *score_max) { + *score_max = score_ret; + } + + // Free the temporary buffer + av_free(aligned_buf); + + return (lp_ac_proberesult)fmt; +} + +AVInputFormat *ac_probe_input_stream(void *sender, ac_read_callback read_proc, + char *filename, uint8_t **buf, + size_t *buf_read) +{ + // Initialize the result variables + AVInputFormat *fmt = NULL; + *buf_read = 0; + *buf = NULL; + int last_iteration = 0; + int probe_size = 0; + + for (probe_size = PROBE_BUF_MIN; + (probe_size <= PROBE_BUF_MAX) && !fmt && !last_iteration; + probe_size <<= 1) { + int score = AVPROBE_SCORE_MAX / 4; + + // Allocate some memory for the current probe buffer + uint8_t *tmp_buf = av_malloc(probe_size); + memset(tmp_buf, 0, probe_size); + + // Copy the old data to the new buffer + if (*buf) { + memcpy(tmp_buf, *buf, *buf_read); + // Free the old data memory + av_free(*buf); + } + + // Read the new data + uint8_t *write_ptr = tmp_buf + *buf_read; + int read_size = probe_size - (int)*buf_read; + int size = read_proc(sender, write_ptr, read_size); + if (size < 0) { + return fmt; // An error occurred, abort + } + if (size < read_size) { + last_iteration = 1; + probe_size = (int)*buf_read + size; + } + + // Probe it + fmt = (AVInputFormat *)ac_probe_input_buffer(tmp_buf, probe_size, + filename, &score); + + // Set the new buffer + *buf = tmp_buf; + *buf_read = probe_size; + } + + // Return the result + return fmt; +} + +static void cpymetadata(const AVFormatContext *ctx, const char *key, char *tar, + size_t len) +{ + const AVDictionaryEntry *entry = av_dict_get(ctx->metadata, key, NULL, 0); + if (entry) { + strncpy_s(tar, len, entry->value, len); + } else { + strncpy_s(tar, len, "", len); + } +} + +static void cpymetadatai(const AVFormatContext *ctx, const char *key, int *tar) +{ + char buf[16]; + cpymetadata(ctx, key, buf, 16); + *tar = atoi(buf); +} + +static int finalize_open(lp_ac_instance pacInstance) +{ + lp_ac_data self = ((lp_ac_data)pacInstance); + + // Assume the stream is opened + pacInstance->opened = 1; + + // Retrieve stream information + AVFormatContext *ctx = self->pFormatCtx; + if (avformat_find_stream_info(ctx, NULL) >= 0) { + cpymetadata(ctx, "title", pacInstance->info.title, 512); + cpymetadata(ctx, "artist", pacInstance->info.author, 512); + cpymetadata(ctx, "copyright", pacInstance->info.copyright, 512); + cpymetadata(ctx, "comment", pacInstance->info.comment, 512); + cpymetadata(ctx, "album", pacInstance->info.album, 512); + cpymetadata(ctx, "genre", pacInstance->info.genre, 32); + cpymetadatai(ctx, "year", &(pacInstance->info.year)); + cpymetadatai(ctx, "track", &(pacInstance->info.track)); + pacInstance->info.bitrate = (int)ctx->bit_rate; + pacInstance->info.duration = ctx->duration * 1000 / AV_TIME_BASE; + } else { + ac_close(pacInstance); + return -1; + } + + // Set some information in the instance variable + pacInstance->stream_count = + ((lp_ac_data)pacInstance)->pFormatCtx->nb_streams; + if (pacInstance->stream_count <= 0) { + ac_close(pacInstance); + return -1; + } + return 0; +} + +int CALL_CONVT ac_open(lp_ac_instance pacInstance, void *sender, + ac_openclose_callback open_proc, + ac_read_callback read_proc, ac_seek_callback seek_proc, + ac_openclose_callback close_proc, + lp_ac_proberesult proberesult) +{ + // Instance cannot be opened twice! + if (pacInstance->opened) { + return -1; + } + + // Reference at the underlying lp_ac_data instance + lp_ac_data self = ((lp_ac_data)pacInstance); + + // Store the given parameters in the ac Instance + self->sender = sender; + self->open_proc = open_proc; + self->read_proc = read_proc; + self->seek_proc = seek_proc; + self->close_proc = close_proc; + + // Call the file open proc + if (self->open_proc != NULL) { + if (self->open_proc(sender) < 0) { + return -1; + } + } + + AVInputFormat *fmt = NULL; + + // Probe the input format, if no probe result is specified + if (proberesult == NULL) { + fmt = + ac_probe_input_stream(sender, read_proc, "", &(self->probe_buffer), + &(self->probe_buffer_size)); + } else { + fmt = (AVInputFormat *)proberesult; + } + + if (!fmt) { + ac_close(pacInstance); + return -1; + } + + // Reserve the buffer memory and initialise the context + self->buffer = av_malloc(AC_BUFSIZE); + self->pIo = avio_alloc_context(self->buffer, AC_BUFSIZE, 0, self, io_read, + 0, seek_proc ? io_seek : NULL); + self->pIo->seekable = seek_proc != NULL; + + // Open the given input stream (the io structure) with the given format of + // the stream (fmt) and write the pointer to the new format context to the + // pFormatCtx variable + self->pFormatCtx = avformat_alloc_context(); + self->pFormatCtx->pb = self->pIo; + if (avformat_open_input(&(self->pFormatCtx), "", fmt, NULL) < 0) { + ac_close(pacInstance); + return -1; + } + + return finalize_open(pacInstance); +} + +int CALL_CONVT ac_open_file(lp_ac_instance pacInstance, const char *filename) +{ + // Instance cannot be opened twice! + if (pacInstance->opened) { + return -1; + } + + // Reference at the underlying lp_ac_data instance + lp_ac_data self = ((lp_ac_data)pacInstance); + + self->pFormatCtx = NULL; + if (avformat_open_input(&(self->pFormatCtx), filename, NULL, NULL) < 0) { + ac_close(pacInstance); + return -1; + } + + return finalize_open(pacInstance); +} + +void CALL_CONVT ac_close(lp_ac_instance pacInstance) +{ + lp_ac_data self = ((lp_ac_data)pacInstance); + if (pacInstance->opened) { + // Close the opened file + if (self->close_proc != NULL) { + self->close_proc(((lp_ac_data)(pacInstance))->sender); + } + + avformat_close_input(&(self->pFormatCtx)); + + pacInstance->opened = 0; + } + + // Make sure all buffers are freed + av_free(self->probe_buffer); + av_free(self->buffer); + av_free(self->pIo); + self->buffer = NULL; + self->probe_buffer = NULL; + self->pIo = NULL; + self->pFormatCtx = NULL; + self->sender = NULL; + self->open_proc = NULL; + self->read_proc = NULL; + self->seek_proc = NULL; + self->close_proc = NULL; +} + +void CALL_CONVT ac_get_stream_info(lp_ac_instance pacInstance, int nb, + lp_ac_stream_info info) +{ + // Rese the stream info structure + memset(info, 0, sizeof(ac_stream_info)); + info->stream_type = AC_STREAM_TYPE_UNKNOWN; + + // Abort if the instance is not opened + if (!(pacInstance->opened)) { + return; + } + + // Read the information + lp_ac_data self = ((lp_ac_data)pacInstance); + switch (self->pFormatCtx->streams[nb]->codecpar->codec_type) { + case AVMEDIA_TYPE_VIDEO: + // Set stream type to "VIDEO" + info->stream_type = AC_STREAM_TYPE_VIDEO; + + // Store more information about the video stream + info->additional_info.video_info.frame_width = + self->pFormatCtx->streams[nb]->codecpar->width; + info->additional_info.video_info.frame_height = + self->pFormatCtx->streams[nb]->codecpar->height; + + double pixel_aspect_num = + self->pFormatCtx->streams[nb]->codecpar->sample_aspect_ratio.num; + double pixel_aspect_den = + self->pFormatCtx->streams[nb]->codecpar->sample_aspect_ratio.den; + + // Sometime "pixel aspect" may be zero or have other invalid values. + // Correct this. + if (pixel_aspect_num <= 0.0 || pixel_aspect_den <= 0.0) + info->additional_info.video_info.pixel_aspect = 1.0; + else + info->additional_info.video_info.pixel_aspect = (float)( + pixel_aspect_num / pixel_aspect_den); + + info->additional_info.video_info.frames_per_second = + (double)self->pFormatCtx->streams[nb]->r_frame_rate.num / + (double)self->pFormatCtx->streams[nb]->r_frame_rate.den; + break; + case AVMEDIA_TYPE_AUDIO: + // Set stream type to "AUDIO" + info->stream_type = AC_STREAM_TYPE_AUDIO; + + // Store more information about the video stream + info->additional_info.audio_info.samples_per_second = + self->pFormatCtx->streams[nb]->codecpar->sample_rate; + info->additional_info.audio_info.channel_count = + self->pFormatCtx->streams[nb]->codecpar->channels; + + // Set bit depth + switch (self->pFormatCtx->streams[nb]->codecpar->format) { + // 8-Bit + case AV_SAMPLE_FMT_U8: + case AV_SAMPLE_FMT_U8P: + info->additional_info.audio_info.bit_depth = 8; + break; + + // 16-Bit + case AV_SAMPLE_FMT_S16: + case AV_SAMPLE_FMT_S16P: + info->additional_info.audio_info.bit_depth = 16; + break; + + /* //24-Bit (removed in the newest ffmpeg version) + case SAMPLE_FMT_S24: + info->additional_info.audio_info.bit_depth = + 24; + break; */ + + // 32-Bit + case AV_SAMPLE_FMT_S32: + case AV_SAMPLE_FMT_FLT: + case AV_SAMPLE_FMT_DBL: + case AV_SAMPLE_FMT_S32P: + case AV_SAMPLE_FMT_FLTP: + case AV_SAMPLE_FMT_DBLP: + info->additional_info.audio_info.bit_depth = 32; + break; + + // Unknown format, return zero + default: + info->additional_info.audio_info.bit_depth = 0; + } + + break; + default: { + // Do nothing + } + } } // //---Package management--- // -lp_ac_package CALL_CONVT ac_read_package(lp_ac_instance pacInstance) { - //Try to read package - AVPacket Package; - if (av_read_frame(((lp_ac_data)(pacInstance))->pFormatCtx, &Package) >= 0) { - //Reserve memory - lp_ac_package_data pTmp = (lp_ac_package_data)(av_malloc(sizeof(ac_package_data))); - memset(pTmp, 0, sizeof(ac_package_data)); - - //Set package data - pTmp->package.stream_index = Package.stream_index; - pTmp->ffpackage = Package; - - if (Package.dts != AV_NOPTS_VALUE) { - pTmp->pts = Package.dts; - } - - return (lp_ac_package)(pTmp); - } else { +lp_ac_package CALL_CONVT ac_read_package(lp_ac_instance pacInstance) +{ + // Allocate the result packet + lp_ac_package_data pkt = av_malloc(sizeof(ac_package_data)); + memset(pkt, 0, sizeof(ac_package_data)); + pkt->pPack = av_malloc(sizeof(AVPacket)); + + av_init_packet(pkt->pPack); + pkt->pPack->data = NULL; + pkt->pPack->size = 0; + + // Try to read package + if (av_read_frame(((lp_ac_data)(pacInstance))->pFormatCtx, pkt->pPack) >= + 0) { + if (pkt->pPack->dts != AV_NOPTS_VALUE) { + pkt->pts = (int)pkt->pPack->dts; + } + pkt->package.stream_index = pkt->pPack->stream_index; + return (lp_ac_package)(pkt); + } + ac_free_package((lp_ac_package)pkt); return NULL; - } } -//Frees the currently loaded package +// Frees the currently loaded package void CALL_CONVT ac_free_package(lp_ac_package pPackage) { - //Free the packet - if (pPackage != NULL) { - AVPacket* pkt = &((lp_ac_package_data)pPackage)->ffpackage; - if (pkt) { - if (pkt->destruct){pkt->destruct = av_destruct_packet; pkt->destruct(pkt);} //FIXME: workaround for deprecation of AVPacket::destruct - pkt->data = NULL; pkt->size = 0; - } - av_free((lp_ac_package_data)pPackage); - } + if (pPackage) { + lp_ac_package_data self = (lp_ac_package_data)pPackage; + if (self->pPack) { + if (self->pPack->buf) { + av_buffer_unref(&self->pPack->buf); + } + self->pPack->data = NULL; + self->pPack->size = 0; + + av_packet_free_side_data(self->pPack); + } + av_free(self->pPack); + av_free(self); + } } // //--- Decoder management --- // -enum PixelFormat convert_pix_format(ac_output_format fmt) { - switch (fmt) { - case AC_OUTPUT_RGB24: return PIX_FMT_RGB24; - case AC_OUTPUT_BGR24: return PIX_FMT_BGR24; - case AC_OUTPUT_RGBA32: return PIX_FMT_RGB32; - case AC_OUTPUT_BGRA32: return PIX_FMT_BGR32; - } - return PIX_FMT_RGB32; -} - -lp_ac_decoder CALL_CONVT ac_create_video_decoder(lp_ac_instance pacInstance) { - //Allocate memory for a new decoder instance - lp_ac_video_decoder pDecoder; - pDecoder = (lp_ac_video_decoder)(av_malloc(sizeof(ac_video_decoder))); - memset(pDecoder, 0, sizeof(ac_video_decoder)); - - int nb = av_find_best_stream(((lp_ac_data)pacInstance)->pFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); - if (nb < 0) - return NULL; - - ac_stream_info info; - ac_get_stream_info(pacInstance, nb, &info); - - //Set a few properties - pDecoder->decoder.pacInstance = pacInstance; - pDecoder->decoder.type = AC_DECODER_TYPE_VIDEO; - pDecoder->decoder.stream_index = nb; - pDecoder->decoder.video_clock = 0; - pDecoder->pCodecCtx = ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec; - pDecoder->decoder.stream_info = info; - pDecoder->pCodecCtx->thread_count = 1; //this is for HT CPUs, it should be - // tested if there is a better solution - - //Find correspondenting codec - if (!(pDecoder->pCodec = avcodec_find_decoder(pDecoder->pCodecCtx->codec_id))) - return NULL; //Codec could not have been found - - //Open codec - if (avcodec_open2(pDecoder->pCodecCtx, pDecoder->pCodec, NULL) < 0) - return NULL; //Codec could not have been opened - - //Reserve frame variables - pDecoder->pFrame = avcodec_alloc_frame(); - pDecoder->pFrameRGB = avcodec_alloc_frame(); - - pDecoder->pSwsCtx = NULL; - - //Reserve buffer memory - pDecoder->decoder.buffer_size = avpicture_get_size(convert_pix_format(pacInstance->output_format), - pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height); - pDecoder->decoder.pBuffer = (uint8_t*)av_malloc(pDecoder->decoder.buffer_size); - - //Link decoder to buffer - avpicture_fill( - (AVPicture*)(pDecoder->pFrameRGB), - pDecoder->decoder.pBuffer, convert_pix_format(pacInstance->output_format), - pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height); - - return (void*)pDecoder; -} - -lp_ac_decoder CALL_CONVT ac_create_audio_decoder(lp_ac_instance pacInstance) +enum AVPixelFormat convert_pix_format(ac_output_format fmt) { - //Allocate memory for a new decoder instance - lp_ac_audio_decoder pDecoder; - pDecoder = (lp_ac_audio_decoder)(av_malloc(sizeof(ac_audio_decoder))); - memset(pDecoder, 0, sizeof(ac_audio_decoder)); - - int nb = av_find_best_stream(((lp_ac_data)pacInstance)->pFormatCtx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0); - if (nb < 0) - return NULL; - - ac_stream_info info; - ac_get_stream_info(pacInstance, nb, &info); - - //Set a few properties - pDecoder->decoder.pacInstance = pacInstance; - pDecoder->decoder.type = AC_DECODER_TYPE_AUDIO; - pDecoder->decoder.stream_index = nb; - pDecoder->decoder.stream_info = info; - pDecoder->decoder.video_clock = 0; - - //Temporary store codec context pointer - AVCodecContext *pCodecCtx = ((lp_ac_data)pacInstance)->pFormatCtx->streams[nb]->codec; - pDecoder->pCodecCtx = pCodecCtx; - //pDecoder->pCodecCtx->thread_count = 1; //this is for HT CPUs, it should be - // tested if there is a better solution - - //Find correspondenting codec - if (!(pDecoder->pCodec = avcodec_find_decoder(pCodecCtx->codec_id))) - return NULL; - - //Open codec - if (avcodec_open2(pCodecCtx, pDecoder->pCodec, NULL) < 0) - return NULL; - - //Initialize the buffers - pDecoder->decoder.pBuffer = av_malloc(AUDIO_BUFFER_BASE_SIZE); - pDecoder->decoder.buffer_size = 0; - pDecoder->max_buffer_size = AUDIO_BUFFER_BASE_SIZE; - - return (void*)pDecoder; -} - -double ac_sync_video(lp_ac_package pPackage, lp_ac_decoder pDec, AVFrame *src_frame, double pts){ - double frame_delay; - - if(pts != 0){ - pDec->video_clock = pts; - } else { - pts = pDec->video_clock; - } - - frame_delay = av_q2d(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->time_base); - frame_delay += src_frame->repeat_pict * (frame_delay * 0.5); - pDec->video_clock += frame_delay; - return pts; -} - -int ac_decode_video_package(lp_ac_package pPackage, lp_ac_video_decoder pDecoder, lp_ac_decoder pDec) -{ - int finished = 0; - double pts = 0; - int len = 0; - - AVPacket pkt_tmp = ((lp_ac_package_data)pPackage)->ffpackage; - - while (pkt_tmp.size > 0) { - len = avcodec_decode_video2( - pDecoder->pCodecCtx, pDecoder->pFrame, - &finished, &pkt_tmp); - - if (len < 0) { - return 0; + switch (fmt) { + case AC_OUTPUT_RGB24: + return AV_PIX_FMT_RGB24; + case AC_OUTPUT_BGR24: + return AV_PIX_FMT_BGR24; + case AC_OUTPUT_RGBA32: + return AV_PIX_FMT_RGB32; + case AC_OUTPUT_BGRA32: + return AV_PIX_FMT_BGR32; + case AC_OUTPUT_YUV420P: + return AV_PIX_FMT_YUV420P; + case AC_OUTPUT_UYVY422: + return AV_PIX_FMT_UYVY422; + case AC_OUTPUT_YUYV422: + return AV_PIX_FMT_YUYV422; } + return AV_PIX_FMT_RGB24; +} - pkt_tmp.size -= len; - pkt_tmp.data += len; - } +// Init a video decoder +void *ac_create_video_decoder(lp_ac_instance pacInstance, + lp_ac_stream_info info, int nb) +{ + // Allocate memory for a new decoder instance + lp_ac_video_decoder pDecoder; + pDecoder = (lp_ac_video_decoder)(av_malloc(sizeof(ac_video_decoder))); + memset(pDecoder, 0, sizeof(ac_video_decoder)); + + // Set a few properties + pDecoder->decoder.pacInstance = pacInstance; + pDecoder->decoder.type = AC_DECODER_TYPE_VIDEO; + pDecoder->decoder.stream_index = nb; - if (finished != 0) { - pDecoder->pSwsCtx = sws_getCachedContext(pDecoder->pSwsCtx, - pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height, pDecoder->pCodecCtx->pix_fmt, - pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height, convert_pix_format(pDecoder->decoder.pacInstance->output_format), - SWS_FAST_BILINEAR, NULL, NULL, NULL); - - sws_scale( - pDecoder->pSwsCtx, - (const uint8_t* const*)(pDecoder->pFrame->data), - pDecoder->pFrame->linesize, - 0, //? - pDecoder->pCodecCtx->height, - pDecoder->pFrameRGB->data, - pDecoder->pFrameRGB->linesize); - - - if(pkt_tmp.dts == AV_NOPTS_VALUE && - *(uint64_t*)pDecoder->pFrame->opaque != AV_NOPTS_VALUE ){ - pts = *(uint64_t*)pDecoder->pFrame->opaque; - } else if(pkt_tmp.dts != AV_NOPTS_VALUE){ - pts = pkt_tmp.dts; + AVCodecParameters* pCodecParam = ((lp_ac_data)(pacInstance))->pFormatCtx->streams[nb]->codecpar; + pDecoder->decoder.stream_info = *info; + + // Find correspondenting codec + if (!(pDecoder->pCodec = + avcodec_find_decoder(pCodecParam->codec_id))) { + return NULL; // Codec could not have been found } - - if(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->start_time != AV_NOPTS_VALUE){ - pts -= ((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->start_time; - } - pts *= av_q2d(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->time_base); - - pts = ac_sync_video(pPackage, pDec, pDecoder->pFrame, pts); - pDec->timecode = pts; - - return 1; - } - return 0; + pDecoder->pCodecCtx = avcodec_alloc_context3(pDecoder->pCodec); + avcodec_parameters_to_context(pDecoder->pCodecCtx, pCodecParam); + + // Open codec + if (avcodec_open2(pDecoder->pCodecCtx, pDecoder->pCodec, NULL) < 0) { + return NULL; // Codec could not have been opened + } + + // Reserve frame variables + pDecoder->pFrame = av_frame_alloc(); + pDecoder->pFrameRGB = av_frame_alloc(); + + pDecoder->pSwsCtx = NULL; + + // Reserve buffer memory + pDecoder->decoder.buffer_size = av_image_get_buffer_size( + convert_pix_format(pacInstance->output_format), + pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height, + 1); + pDecoder->decoder.pBuffer = + (uint8_t *)av_malloc(pDecoder->decoder.buffer_size); + + // Link decoder to buffer + av_image_fill_arrays(pDecoder->pFrameRGB->data, + pDecoder->pFrameRGB->linesize, + pDecoder->decoder.pBuffer, + convert_pix_format(pacInstance->output_format), + pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height, + 1); + + return (void *)pDecoder; } -int alloc_samples_array_and_data(uint8_t ***data, int *linesize, int nb_channels, int nb_samples, enum AVSampleFormat sample_fmt, int align) +// Init a audio decoder +void *ac_create_audio_decoder(lp_ac_instance pacInstance, + lp_ac_stream_info info, int nb) { - int nb_planes = av_sample_fmt_is_planar(sample_fmt) ? nb_channels : 1; + // Allocate memory for a new decoder instance + lp_ac_data self = ((lp_ac_data)(pacInstance)); + lp_ac_audio_decoder pDecoder = NULL; + ERR(pDecoder = (lp_ac_audio_decoder)(av_malloc(sizeof(ac_audio_decoder)))); + memset(pDecoder, 0, sizeof(ac_audio_decoder)); - *data = av_malloc(sizeof(*data) * nb_planes); - if (!*data) - return AVERROR(ENOMEM); - return av_samples_alloc(*data, linesize, nb_channels, - nb_samples, sample_fmt, align); -} + // Set a few properties + pDecoder->decoder.pacInstance = pacInstance; + pDecoder->decoder.type = AC_DECODER_TYPE_AUDIO; + pDecoder->decoder.stream_index = nb; + pDecoder->decoder.stream_info = *info; + + AVCodecParameters* pCodecParam = self->pFormatCtx->streams[nb]->codecpar; -int ac_decode_audio_package(lp_ac_package pPackage, lp_ac_audio_decoder pDecoder, lp_ac_decoder pDec) { - double pts; - //Variables describing the destination buffer - int dest_buffer_pos = pDecoder->decoder.buffer_size; - - //Make a copy of the package read by avformat, so that we can move the data pointers around - AVPacket pkt_tmp = ((lp_ac_package_data)pPackage)->ffpackage; - AVFrame *decoded_frame = NULL; + // Find correspondenting codec + ERR(pDecoder->pCodec = avcodec_find_decoder(pCodecParam->codec_id)); - while (pkt_tmp.size > 0) { - - if (!decoded_frame) { - if (!(decoded_frame = avcodec_alloc_frame())) { - return 0; + pDecoder->pCodecCtx = avcodec_alloc_context3(pDecoder->pCodec); + avcodec_parameters_to_context(pDecoder->pCodecCtx, pCodecParam); + + // Open codec + AV_ERR(avcodec_open2(pDecoder->pCodecCtx, pDecoder->pCodec, NULL)); + + // Initialize the buffers + pDecoder->decoder.pBuffer = NULL; // av_malloc(AUDIO_BUFFER_BASE_SIZE); + pDecoder->decoder.buffer_size = 0; + ERR(pDecoder->pFrame = av_frame_alloc()); + + // Fetch audio format, rate and channel layout -- under some circumstances, + // the layout is not known to the decoder, then a channel layout is guessed + // from the channel count. + const enum AVSampleFormat fmt = pDecoder->pCodecCtx->sample_fmt; + const int rate = pDecoder->pCodecCtx->sample_rate; + const int64_t layout = + pDecoder->pCodecCtx->channel_layout + ? pDecoder->pCodecCtx->channel_layout + : av_get_default_channel_layout(pDecoder->pCodecCtx->channels); + + // Initialize libswresample if needed + if (av_sample_fmt_is_planar(fmt) || (fmt == AV_SAMPLE_FMT_S32) || + (fmt == AV_SAMPLE_FMT_DBL)) { + enum AVSampleFormat out_fmt = av_get_packed_sample_fmt(fmt); + if (out_fmt == AV_SAMPLE_FMT_DBL || out_fmt == AV_SAMPLE_FMT_S32) { + out_fmt = AV_SAMPLE_FMT_FLT; } - } else - avcodec_get_frame_defaults(decoded_frame); - - int got_frame = 0; - - int len1 = avcodec_decode_audio4(pDecoder->pCodecCtx, decoded_frame, &got_frame, &pkt_tmp); - - //If an error occured, skip the frame - if (len1 < 0){ - return 0; + pDecoder->pSwrCtx = swr_alloc_set_opts(NULL, layout, out_fmt, rate, + layout, fmt, rate, 0, NULL); + AV_ERR(swr_init(pDecoder->pSwrCtx)); } - - //Increment the source buffer pointers - pkt_tmp.size -= len1; - pkt_tmp.data += len1; + return (void *)pDecoder; + +error: + ac_free_audio_decoder(pDecoder); + return NULL; +} + +lp_ac_decoder CALL_CONVT ac_create_decoder(lp_ac_instance pacInstance, int nb) +{ + // Get information about the chosen data stream and create an decoder that + // can handle this kind of stream. + ac_stream_info info; + ac_get_stream_info(pacInstance, nb, &info); + + lp_ac_decoder_data result = NULL; + + if (info.stream_type == AC_STREAM_TYPE_VIDEO) { + result = + (lp_ac_decoder_data)ac_create_video_decoder(pacInstance, &info, nb); + } else if (info.stream_type == AC_STREAM_TYPE_AUDIO) { + result = + (lp_ac_decoder_data)ac_create_audio_decoder(pacInstance, &info, nb); + } + + if (result) { + result->decoder.timecode = 0; + result->last_timecode = 0; + result->sought = 1; + } + + return (lp_ac_decoder)result; +} + +int ac_decode_video_package(lp_ac_package pPackage, + lp_ac_video_decoder pDecoder) +{ + lp_ac_package_data pkt = ((lp_ac_package_data)pPackage); + + if(avcodec_send_packet(pDecoder->pCodecCtx, pkt->pPack) != 0) + { + return 0; + } + + if (avcodec_receive_frame(pDecoder->pCodecCtx, pDecoder->pFrame) != 0) + { + return 0; + } + + pDecoder->pSwsCtx = sws_getCachedContext( + pDecoder->pSwsCtx, pDecoder->pCodecCtx->width, + pDecoder->pCodecCtx->height, pDecoder->pCodecCtx->pix_fmt, + pDecoder->pCodecCtx->width, pDecoder->pCodecCtx->height, + convert_pix_format(pDecoder->decoder.pacInstance->output_format), + SWS_BICUBIC, NULL, NULL, NULL); + + sws_scale(pDecoder->pSwsCtx, + (const uint8_t *const *)(pDecoder->pFrame->data), + pDecoder->pFrame->linesize, + 0, //? + pDecoder->pCodecCtx->height, pDecoder->pFrameRGB->data, + pDecoder->pFrameRGB->linesize); + return 1; - if (got_frame){ - struct SwrContext *swr_ctx; - int dst_nb_samples = 0, max_dst_nb_samples = 0, dst_linesize = 0; - uint8_t **dst_data = NULL; - int ret = 0; - int dst_sample_rate = (pDecoder->pCodecCtx)->sample_rate; - - swr_ctx = swr_alloc(); - - /* set options */ - av_opt_set_int(swr_ctx, "in_channel_layout", (pDecoder->pCodecCtx)->channel_layout, 0); - av_opt_set_int(swr_ctx, "in_sample_rate", (pDecoder->pCodecCtx)->sample_rate, 0); - av_opt_set_sample_fmt(swr_ctx, "in_sample_fmt", (pDecoder->pCodecCtx)->sample_fmt, 0); +} - av_opt_set_int(swr_ctx, "out_channel_layout", AV_CH_LAYOUT_STEREO, 0); - av_opt_set_int(swr_ctx, "out_sample_rate", dst_sample_rate, 0); - av_opt_set_sample_fmt(swr_ctx, "out_sample_fmt", AV_SAMPLE_FMT_S16, 0); - - if (swr_init(swr_ctx) < 0) - return 0; +int ac_skip_video_package(lp_ac_package pPackage, + lp_ac_video_decoder pDecoder) +{ + lp_ac_package_data pkt = ((lp_ac_package_data)pPackage); - /* compute the number of converted samples: buffering is avoided - * ensuring that the output buffer will contain at least all the - * converted input samples */ - max_dst_nb_samples = dst_nb_samples = av_rescale_rnd( - decoded_frame->nb_samples, dst_sample_rate, (pDecoder->pCodecCtx)->sample_rate, AV_ROUND_UP); - - if (alloc_samples_array_and_data(&dst_data, &dst_linesize, 2, dst_nb_samples, AV_SAMPLE_FMT_S16, 0) < 0) - return 0; - - /* compute destination number of samples */ - dst_nb_samples = av_rescale_rnd(swr_get_delay(swr_ctx, (pDecoder->pCodecCtx)->sample_rate) + - decoded_frame->nb_samples, dst_sample_rate, (pDecoder->pCodecCtx)->sample_rate, AV_ROUND_UP); - - if (dst_nb_samples > max_dst_nb_samples) { - av_free(dst_data[0]); - ret = av_samples_alloc(dst_data, &dst_linesize, 2, - dst_nb_samples, AV_SAMPLE_FMT_S16, 1); - if (ret < 0) - return 0; - max_dst_nb_samples = dst_nb_samples; - } - - if ((ret = swr_convert(swr_ctx, dst_data, dst_nb_samples, (const uint8_t **)decoded_frame->data, decoded_frame->nb_samples)) < 0) - return 0; - - int data_size = av_samples_get_buffer_size(&dst_linesize, 2, ret, AV_SAMPLE_FMT_S16, 1); - - //Reserve enough memory for coping the result data - if (dest_buffer_pos + data_size > pDecoder->max_buffer_size) { - pDecoder->decoder.pBuffer = av_realloc(pDecoder->decoder.pBuffer, dest_buffer_pos + data_size); - pDecoder->max_buffer_size = dest_buffer_pos + data_size; - } - - memcpy(pDecoder->decoder.pBuffer + dest_buffer_pos, dst_data[0], data_size); - - //Increment the destination buffer pointers, copy the result to the output buffer - dest_buffer_pos += data_size; - pDecoder->decoder.buffer_size += data_size; - - pts=0; + if (avcodec_send_packet(pDecoder->pCodecCtx, pkt->pPack) != 0) + { + return 0; + } - if(((lp_ac_package_data)pPackage)->ffpackage.dts != AV_NOPTS_VALUE){ - pts = ((lp_ac_package_data)pPackage)->ffpackage.dts * av_q2d(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->time_base); - - pDec->video_clock = pts; - } else { - pts = pDec->video_clock; - } - - double bytes_per_second = 4 * pDec->stream_info.audio_info.samples_per_second; - if (bytes_per_second > 0) - pDec->video_clock += data_size / bytes_per_second; - - pDec->timecode = pts; - - if (dst_data) - av_freep(&dst_data[0]); - av_freep(&dst_data); + if (avcodec_receive_frame(pDecoder->pCodecCtx, pDecoder->pFrame) != 0) + { + return 0; + } + + return 1; +} - swr_free(&swr_ctx); - return 1; - } - } - - return 0; +int ac_decode_audio_package(lp_ac_package pPackage, + lp_ac_audio_decoder pDecoder) +{ + int got_frame = 0; + int len = 0; + lp_ac_package_data pkt = ((lp_ac_package_data)pPackage); + + if (avcodec_send_packet(pDecoder->pCodecCtx, pkt->pPack) != 0) + { + return 0; + } + + if (avcodec_receive_frame(pDecoder->pCodecCtx, pDecoder->pFrame) != 0) + { + return 0; + } + + // Calculate the output buffer size + const int sample_size = + MIN(4, av_get_bytes_per_sample(pDecoder->pCodecCtx->sample_fmt)); + const int sample_count = pDecoder->pFrame->nb_samples; + const int channel_count = pDecoder->pFrame->channels; + const int buffer_size = sample_size * sample_count * channel_count; + pDecoder->decoder.buffer_size = buffer_size; + + if (pDecoder->pSwrCtx) { + if (pDecoder->own_buffer_size != buffer_size) { + pDecoder->decoder.pBuffer = + av_realloc(pDecoder->decoder.pBuffer, buffer_size); + pDecoder->own_buffer_size = buffer_size; + } + swr_convert(pDecoder->pSwrCtx, &(pDecoder->decoder.pBuffer), + sample_count, (const uint8_t **)(pDecoder->pFrame->data), + sample_count); + } else { + // No conversion needs to be done, simply set the buffer pointer + pDecoder->decoder.pBuffer = pDecoder->pFrame->data[0]; + } + + return got_frame; +} + +int ac_skip_audio_package(lp_ac_package pPackage, + lp_ac_audio_decoder pDecoder) +{ + int got_frame = 0; + int len = 0; + lp_ac_package_data pkt = ((lp_ac_package_data)pPackage); + if (avcodec_send_packet(pDecoder->pCodecCtx, pkt->pPack) != 0) + { + return 0; + } + + if (avcodec_receive_frame(pDecoder->pCodecCtx, pDecoder->pFrame) != 0) + { + return 0; + } + + return got_frame; } int CALL_CONVT ac_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder) { - if (pDecoder->type == AC_DECODER_TYPE_AUDIO) - return ac_decode_audio_package(pPackage, (lp_ac_audio_decoder)pDecoder, pDecoder); - else if (pDecoder->type == AC_DECODER_TYPE_VIDEO) - return ac_decode_video_package(pPackage, (lp_ac_video_decoder)pDecoder, pDecoder); + double timebase = av_q2d(((lp_ac_data)pDecoder->pacInstance) + ->pFormatCtx->streams[pPackage->stream_index] + ->time_base); - return 0; -} + // Create a valid timecode + if (((lp_ac_package_data)pPackage)->pts > 0) { + lp_ac_decoder_data dec_dat = (lp_ac_decoder_data)pDecoder; -int CALL_CONVT ac_drop_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder) -{ - if (pDecoder->type == AC_DECODER_TYPE_VIDEO) { - return ac_drop_decode_video_package(pPackage, (lp_ac_video_decoder)pDecoder, pDecoder); - } - return 0; -} + dec_dat->last_timecode = pDecoder->timecode; + pDecoder->timecode = ((lp_ac_package_data)pPackage)->pts * timebase; -int ac_drop_decode_video_package(lp_ac_package pPackage, lp_ac_video_decoder pDecoder, lp_ac_decoder pDec) { - int finished; - double pts; - int len = 0; + double delta = pDecoder->timecode - dec_dat->last_timecode; + double max_delta, min_delta; - AVPacket pkt_tmp = ((lp_ac_package_data)pPackage)->ffpackage; - - while (pkt_tmp.size > 0) { - len = avcodec_decode_video2( - pDecoder->pCodecCtx, pDecoder->pFrame, - &finished, &pkt_tmp); - - if (len < 0) { - return 0; + if (dec_dat->sought > 0) { + max_delta = 120.0; + min_delta = -120.0; + --dec_dat->sought; + } else { + max_delta = 4.0; + min_delta = 0.0; + } + + if ((delta < min_delta) || (delta > max_delta)) { + pDecoder->timecode = dec_dat->last_timecode; + if (dec_dat->sought > 0) { + ++dec_dat->sought; + } + } } - pkt_tmp.size -= len; - pkt_tmp.data += len; - } - - if (finished) { - pts=0; - - if(((lp_ac_package_data)pPackage)->ffpackage.dts == AV_NOPTS_VALUE && - *(uint64_t*)pDecoder->pFrame->opaque != AV_NOPTS_VALUE ){ - pts = *(uint64_t*)pDecoder->pFrame->opaque; - } else if(((lp_ac_package_data)pPackage)->ffpackage.dts != AV_NOPTS_VALUE){ - pts = ((lp_ac_package_data)pPackage)->ffpackage.dts; - } else { - pts = 0; + if (pDecoder->type == AC_DECODER_TYPE_VIDEO) { + return ac_decode_video_package(pPackage, (lp_ac_video_decoder)pDecoder); + } else if (pDecoder->type == AC_DECODER_TYPE_AUDIO) { + return ac_decode_audio_package(pPackage, (lp_ac_audio_decoder)pDecoder); } - - if(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->start_time != AV_NOPTS_VALUE){ - pts -= ((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->start_time; - } - - pts *= av_q2d(((lp_ac_data)pDec->pacInstance)->pFormatCtx->streams[pPackage->stream_index]->time_base); - - pts = ac_sync_video(pPackage, pDec, pDecoder->pFrame, pts); - pDec->timecode = pts; - - return 1; - } - return 0; + return 0; } -int CALL_CONVT ac_get_audio_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder) +int CALL_CONVT ac_skip_package(lp_ac_package pPackage, lp_ac_decoder pDecoder) { - lp_ac_package pPackage = ac_read_package(pacInstance); - ((lp_ac_audio_decoder)pDecoder)->decoder.buffer_size = 0; - - int done = 0; - while(done == 0 && pPackage != NULL){ - if (((lp_ac_package_data)pPackage)->package.stream_index == pDecoder->stream_index) - { - done = ac_decode_package(pPackage, pDecoder); - ac_free_package(pPackage); - - if (done == 0) - pPackage = ac_read_package(pacInstance); - } else { - ac_free_package(pPackage); - pPackage = ac_read_package(pacInstance); - } - } - - if (done == 0) - return 0; - else - return 1; -} + double timebase = av_q2d(((lp_ac_data)pDecoder->pacInstance) + ->pFormatCtx->streams[pPackage->stream_index] + ->time_base); -int CALL_CONVT ac_get_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder) -{ - lp_ac_package pPackage = ac_read_package(pacInstance); - int done = 0; - int pcount = 0; - while(done == 0 && pPackage != NULL){ - if (((lp_ac_package_data)pPackage)->package.stream_index == pDecoder->stream_index) - { - done = ac_decode_package(pPackage, pDecoder); - ac_free_package(pPackage); - pcount++; - if (done == 0) - pPackage = ac_read_package(pacInstance); - } else - { - ac_free_package(pPackage); - pPackage = ac_read_package(pacInstance); - } - } + // Create a valid timecode + if (((lp_ac_package_data)pPackage)->pts > 0) { + lp_ac_decoder_data dec_dat = (lp_ac_decoder_data)pDecoder; - if (done == 0) - return 0; - else - return pcount; + dec_dat->last_timecode = pDecoder->timecode; + pDecoder->timecode = ((lp_ac_package_data)pPackage)->pts * timebase; + + double delta = pDecoder->timecode - dec_dat->last_timecode; + double max_delta, min_delta; + + if (dec_dat->sought > 0) { + max_delta = 120.0; + min_delta = -120.0; + --dec_dat->sought; + } + else { + max_delta = 4.0; + min_delta = 0.0; + } + + if ((delta < min_delta) || (delta > max_delta)) { + pDecoder->timecode = dec_dat->last_timecode; + if (dec_dat->sought > 0) { + ++dec_dat->sought; + } + } + } + + if (pDecoder->type == AC_DECODER_TYPE_VIDEO) { + return ac_skip_video_package(pPackage, (lp_ac_video_decoder)pDecoder); + } + else if (pDecoder->type == AC_DECODER_TYPE_AUDIO) { + return ac_skip_audio_package(pPackage, (lp_ac_audio_decoder)pDecoder); + } + return 0; } int CALL_CONVT ac_skip_frames(lp_ac_instance pacInstance, lp_ac_decoder pDecoder, int num) { - lp_ac_package pPackage = ac_read_package(pacInstance); - - int done = 0; - int i; - for(i=0; i0) - pPackage = ac_read_package(pacInstance); - - done = 0; - while(done == 0 && pPackage != NULL){ - if (((lp_ac_package_data)pPackage)->package.stream_index == pDecoder->stream_index) - { - done = ac_drop_decode_package(pPackage, pDecoder); - ac_free_package(pPackage); - - if (done == 0) - pPackage = ac_read_package(pacInstance); - } else - { - ac_free_package(pPackage); - pPackage = ac_read_package(pacInstance); - } - } - - if (done == 0) - return 0; - } - - if (done == 0) - return 0; - else - return 1; + if (pDecoder == NULL) + { + return 0; + } + + int skipedFrames = 0; + + while (skipedFrames < num) + { + lp_ac_package pckt = ac_read_package(pacInstance); + if (pckt != NULL) + { + // Decode the package to figure out if its completing a frame + if (pckt->stream_index == pDecoder->stream_index && ac_skip_package(pckt, pDecoder) != 0) + { + skipedFrames++; + } + + ac_free_package(pckt); + } + else + { + return 0; + } + } + return 1; } -//Seek function +int CALL_CONVT ac_get_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder) +{ + if (pDecoder == NULL) + { + return 0; + } + + do + { + lp_ac_package pckt = ac_read_package(pacInstance); + if (pckt == NULL) + { + return 0; + } + + if(pckt->stream_index != pDecoder->stream_index) + { + continue; + } + + // The packet is for the video stream, try to decode it + if (ac_decode_package(pckt, pDecoder) != 0) + { + ac_free_package(pckt); + return 1; + } + + ac_free_package(pckt); + + } while (true); +} + +int CALL_CONVT ac_get_audio_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder) +{ + if (pDecoder == NULL) + { + return 0; + } + + do + { + lp_ac_package pckt = ac_read_package(pacInstance); + if (pckt == NULL) + { + return 0; + } + + if (pckt->stream_index != pDecoder->stream_index) + { + continue; + } + + // The packet is for the audio stream, try to decode it + if (ac_decode_package(pckt, pDecoder) != 0) + { + ac_free_package(pckt); + return 1; + } + + ac_free_package(pckt); + + } while (true); +} + +// Seek function int CALL_CONVT ac_seek(lp_ac_decoder pDecoder, int dir, int64_t target_pos) { - AVRational timebase = ((lp_ac_data)pDecoder->pacInstance)->pFormatCtx->streams[pDecoder->stream_index]->time_base; - int flags = dir < 0 ? AVSEEK_FLAG_BACKWARD : 0; - int64_t pos = av_rescale(target_pos, AV_TIME_BASE, 1000); - pDecoder->timecode = target_pos / 1000.0; - pDecoder->video_clock = target_pos / 1000.0; - - if (av_seek_frame(((lp_ac_data)pDecoder->pacInstance)->pFormatCtx, pDecoder->stream_index, - av_rescale_q(pos, AV_TIME_BASE_Q, timebase), flags) >= 0) - { - - if (pDecoder->type == AC_DECODER_TYPE_AUDIO) - { - if (((lp_ac_audio_decoder)pDecoder)->pCodecCtx->codec->flush != NULL) - avcodec_flush_buffers(((lp_ac_audio_decoder)pDecoder)->pCodecCtx); - } - - if (pDecoder->type == AC_DECODER_TYPE_VIDEO) - { - if (((lp_ac_video_decoder)pDecoder)->pCodecCtx->codec->flush != NULL) - avcodec_flush_buffers(((lp_ac_video_decoder)pDecoder)->pCodecCtx); - } - return 1; - } - return 0; + AVRational timebase = ((lp_ac_data)pDecoder->pacInstance) + ->pFormatCtx->streams[pDecoder->stream_index] + ->time_base; + + int flags = dir < 0 ? AVSEEK_FLAG_BACKWARD : 0; + + int64_t pos = av_rescale(target_pos, AV_TIME_BASE, 1000); + + ((lp_ac_decoder_data)pDecoder)->sought = 100; + pDecoder->timecode = (double)target_pos / 1000; + + if (av_seek_frame(((lp_ac_data)pDecoder->pacInstance)->pFormatCtx, + pDecoder->stream_index, + av_rescale_q(pos, AV_TIME_BASE_Q, timebase), + flags) >= 0) { + return 1; + } + + return 0; } -//Free video decoder +// Free video decoder void ac_free_video_decoder(lp_ac_video_decoder pDecoder) -{ - av_free(pDecoder->pFrame); - av_free(pDecoder->pFrameRGB); - - if (pDecoder->pSwsCtx != NULL) - sws_freeContext(pDecoder->pSwsCtx); - - avcodec_close(pDecoder->pCodecCtx); - - //Free reserved memory for the buffer - av_free(pDecoder->decoder.pBuffer); - - //Free reserved memory for decoder record - av_free(pDecoder); +{ + if (pDecoder) { + av_free(pDecoder->pFrame); + av_free(pDecoder->pFrameRGB); + sws_freeContext(pDecoder->pSwsCtx); + avcodec_free_context(&pDecoder->pCodecCtx); + av_free(pDecoder->decoder.pBuffer); + av_free(pDecoder); + } } -//Free video decoder +// Free video decoder void ac_free_audio_decoder(lp_ac_audio_decoder pDecoder) { - avcodec_close(pDecoder->pCodecCtx); - - //Free reserved memory for the buffer - av_free(pDecoder->decoder.pBuffer); - - //Free reserved memory for decoder record - av_free(pDecoder); + if (pDecoder) { + avcodec_free_context(&pDecoder->pCodecCtx); + av_frame_free(&(pDecoder->pFrame)); + if (pDecoder->pSwrCtx) { + swr_free(&(pDecoder->pSwrCtx)); + } + if (pDecoder->own_buffer_size > 0) { + av_free(pDecoder->decoder.pBuffer); + } + av_free(pDecoder); + } } void CALL_CONVT ac_free_decoder(lp_ac_decoder pDecoder) { - if (pDecoder->type == AC_DECODER_TYPE_VIDEO) - ac_free_video_decoder((lp_ac_video_decoder)pDecoder); - else if (pDecoder->type == AC_DECODER_TYPE_AUDIO) - ac_free_audio_decoder((lp_ac_audio_decoder)pDecoder); + if (pDecoder) { + if (pDecoder->type == AC_DECODER_TYPE_VIDEO) { + ac_free_video_decoder((lp_ac_video_decoder)pDecoder); + } else if (pDecoder->type == AC_DECODER_TYPE_AUDIO) { + ac_free_audio_decoder((lp_ac_audio_decoder)pDecoder); + } + } } + diff --git a/Vocaluxe/Lib/Video/Acinerella/acinerella.h b/Vocaluxe/Lib/Video/Acinerella/acinerella.h index bdae2056..a7a228b9 100644 --- a/Vocaluxe/Lib/Video/Acinerella/acinerella.h +++ b/Vocaluxe/Lib/Video/Acinerella/acinerella.h @@ -15,8 +15,8 @@ along with Acinerella. If not, see . */ -#ifndef VIDEOPLAY_H -#define VIDEOPLAY_H +#ifndef _ACINERELLA_H_ +#define _ACINERELLA_H_ #include #include @@ -24,187 +24,495 @@ #ifdef _WIN32 #define CALL_CONVT __cdecl +#define EXTERN extern __declspec(dllexport) #else -#define CALL_CONVT +#define CALL_CONVT +#define EXTERN extern #endif -typedef long long int64; +/** + * Defines the type of an Acinerella media stream. Currently only video and + * audio streams are supported, subtitle and data streams will be marked as + * "unknown". + */ +typedef enum _ac_stream_type { + /** + * The type of the media stream is not known. This kind of stream can not be + * decoded. + */ + AC_STREAM_TYPE_VIDEO = 0, -/*Defines the type of an Acinerella media stream. Currently only video and - audio streams are supported, subtitle and data streams will be marked as - "unknown".*/ -enum _ac_stream_type { - /*The type of the media stream is not known. This kind of stream can not be - decoded.*/ - AC_STREAM_TYPE_VIDEO = 0, - /*This media stream is a video stream.*/ - AC_STREAM_TYPE_AUDIO = 1, - /*This media stream is an audio stream.*/ - AC_STREAM_TYPE_UNKNOWN = -1 -}; + /** + * This media stream is a video stream. + */ + AC_STREAM_TYPE_AUDIO = 1, -typedef enum _ac_stream_type ac_stream_type; + /** + * This media stream is an audio stream. + */ + AC_STREAM_TYPE_UNKNOWN = -1 +} ac_stream_type; -/*Defines the type of an Acinerella media decoder.*/ -enum _ac_decoder_type { - /*This decoder is used to decode a video stream.*/ - AC_DECODER_TYPE_VIDEO = 0, - /* This decoder is used to decode an audio stram.*/ - AC_DECODER_TYPE_AUDIO = 1 -}; +/** + * Defines the type of an Acinerella media decoder. + */ +typedef enum _ac_decoder_type { + /** + * This decoder is used to decode a video stream. + */ + AC_DECODER_TYPE_VIDEO = 0, -typedef enum _ac_decoder_type ac_decoder_type; + /** + * This decoder is used to decode an audio stram. + */ + AC_DECODER_TYPE_AUDIO = 1 +} ac_decoder_type; -/*Defines the format video/image data is outputted in*/ -enum _ac_output_format { - AC_OUTPUT_RGB24 = 0, - AC_OUTPUT_BGR24 = 1, - AC_OUTPUT_RGBA32 = 2, - AC_OUTPUT_BGRA32 = 3 -}; +/** + * Defines the format video/image data is returned in. + */ +typedef enum _ac_output_format { + AC_OUTPUT_RGB24 = 0, + AC_OUTPUT_BGR24 = 1, + AC_OUTPUT_RGBA32 = 2, + AC_OUTPUT_BGRA32 = 3, + AC_OUTPUT_YUV420P = 4, + AC_OUTPUT_UYVY422 = 5, + AC_OUTPUT_YUYV422 = 6 +} ac_output_format; -typedef enum _ac_output_format ac_output_format; - -/*Contains information about the whole file/stream that has been opened. Default values are "" +/*Contains information about the whole file/stream that has been opened. Default +values are "" for strings and -1 for integer values.*/ -struct _ac_file_info { - /*Length of the file*/ - int64_t duration; -}; +typedef struct _ac_file_info { + /** + * Title of the media file + */ + char title[512]; -typedef struct _ac_file_info ac_file_info; -typedef ac_file_info* lp_ac_file_info; + /** + * Author or artist of the media file. + */ + char author[512]; -/*TAc_instance represents an Acinerella instance. Each instance can open and - decode one file at once. There can be only 26 Acinerella instances opened at - once.*/ -struct _ac_instance { - /*If true, the instance currently opened a media file.*/ - bool opened; - /*Contains the count of streams the media file has. This value is available - after calling the ac_open function.*/ - int stream_count; - /*Set this value to change the image output format */ - ac_output_format output_format; - /*Contains information about the opened stream/file*/ - ac_file_info info; -}; + /** + * Copyright information. + */ + char copyright[512]; -typedef struct _ac_instance ac_instance; -/*Pointer on the Acinerella instance record.*/ -typedef ac_instance* lp_ac_instance; + /** + * Comment stored in the file. + */ + char comment[512]; -/*Contains information about an Acinerella video stream.*/ + /** + * Album the media file is from. + */ + char album[512]; + + /** + * Year in which the media file was created. + */ + int year; + + /** + * Track number. + */ + int track; + + /** + * Genre of the media file. + */ + char genre[32]; + + /** + * Length of the file in milliseconds. + */ + int64_t duration; + + /** + * Bitrate of the file. + */ + int bitrate; +} ac_file_info; + +typedef ac_file_info *lp_ac_file_info; + +/** + * ac_instance represents an Acinerella instance. Each instance can open and + * decode one file at once. + */ +typedef struct _ac_instance { + /** + * If true, the instance currently opened a media file. + */ + bool opened; + + /** + * Contains the count of streams the media file has. This value is available + * after calling the ac_open function. + */ + int stream_count; + + /** + * Set this value to change the image output format + */ + ac_output_format output_format; + + /** + * Contains information about the opened stream/file + */ + ac_file_info info; +} ac_instance; + +/** + * Pointer on the Acinerella instance record. + */ +typedef ac_instance *lp_ac_instance; + +/** + * Contains information about an Acinerella video stream. + */ struct _ac_video_stream_info { - /*The width of one frame.*/ - int frame_width; - /*The height of one frame.*/ - int frame_height; - /*The width of one pixel. 1.07 for 4:3 format, 1,42 for the 16:9 format*/ - float pixel_aspect; - /*Frames per second that should be played.*/ - double frames_per_second; -}; -typedef struct _ac_video_stream_info ac_video_stream_info; -/*Contains information about an Acinerella audio stream.*/ -struct _ac_audio_stream_info { - /*Samples per second. Default values are 44100 or 48000.*/ - int samples_per_second; - /*Bits per sample. Can be 8 or 16 Bit.*/ - int bit_depth; - /*Count of channels in the audio stream.*/ - int channel_count; -}; -typedef struct _ac_audio_stream_info ac_audio_stream_info; + /** + * The width of one frame. + */ + int frame_width; + /** + * The height of one frame. + */ + int frame_height; + + /** + * The width of one pixel. 1.07 for 4:3 format, 1,42 for the 16:9 format + */ + float pixel_aspect; + + /** + * Frames per second that should be played. + */ + double frames_per_second; +}; + +/** + * Contains information about an Acinerella audio stream. + */ +struct _ac_audio_stream_info { + /** + * Samples per second. Default values are 44100 or 48000. + */ + int samples_per_second; + + /** + * Bits per sample. Can be 8, 16 or 32 Bit. In the latter case the data is + * in floating point format. + */ + int bit_depth; + + /** + * Count of channels in the audio stream. + */ + int channel_count; +}; + +/** + * Additional info about the stream - use "video_info" when the stream + * is an video stream, "audio_info" when the stream is an audio stream. + */ +union _ac_additional_stream_info { + struct _ac_audio_stream_info audio_info; + struct _ac_video_stream_info video_info; +}; /*Contains information about an Acinerella stream.*/ -struct _ac_stream_info { - /*Contains the type of the stream.*/ - ac_stream_type stream_type; - ac_audio_stream_info audio_info; - ac_video_stream_info video_info; -}; +typedef struct _ac_stream_info { + /** + * Contains the type of the stream. + */ + ac_stream_type stream_type; -typedef struct _ac_stream_info ac_stream_info; -/*Pointer on TAc_stream_info*/ -typedef ac_stream_info* lp_ac_stream_info; + /** + * Additional data depending on the stream type. Either access the + * "audio_info" or the "video_info" field, depending on the value stored in + * the "stream_type" member. + */ + union _ac_additional_stream_info additional_info; +} ac_stream_info; -/*Contains information about an Acinerella video/audio decoder.*/ -struct _ac_decoder { - /*Pointer on the Acinerella instance*/ - lp_ac_instance pacInstance; - /*Contains the type of the decoder.*/ - ac_decoder_type type; - - /*The timecode of the currently decoded picture in seconds */ - double timecode; - - double video_clock; - - /*Contains information about the stream the decoder is attached to.*/ - ac_stream_info stream_info; - /*The index of the stream the decoder is attached to.*/ - int stream_index; - - /*Pointer to the buffer which contains the data.*/ - char *pBuffer; - /*Size of the data in the buffer.*/ - int buffer_size; -}; +/** + * Pointer on ac_stream_info + */ +typedef ac_stream_info *lp_ac_stream_info; -typedef struct _ac_decoder ac_decoder; -/*Pointer on TAc_decoder.*/ -typedef ac_decoder* lp_ac_decoder; +/** + * Contains information about an Acinerella video/audio decoder. + */ +typedef struct _ac_decoder { + /** + * Pointer on the Acinerella instance. + */ + lp_ac_instance pacInstance; -/*Contains information about an Acinerella package.*/ -struct _ac_package { - /*The stream the package belongs to.*/ - int stream_index; -}; + /** + * Contains the type of the decoder. + */ + ac_decoder_type type; -typedef struct _ac_package ac_package; -/*Pointer on TAc_package*/ -typedef ac_package* lp_ac_package; + /** + * The timecode of the currently decoded picture in seconds. + */ + double timecode; -/*Initializes an Acinerella instance.*/ -extern lp_ac_instance CALL_CONVT ac_init(void); -extern void CALL_CONVT ac_free(lp_ac_instance pacInstance); + /** + * Contains information about the stream the decoder is attached to. + */ + ac_stream_info stream_info; -/*Opens a media file.*/ - -extern int CALL_CONVT ac_open2( - lp_ac_instance pacInstance, - const char* filename -); - -/*Closes an opened media file.*/ -extern void CALL_CONVT ac_close(lp_ac_instance pacInstance); - -/*Stores information in "pInfo" about stream number "nb".*/ -extern void CALL_CONVT ac_get_stream_info(lp_ac_instance pacInstance, int nb, lp_ac_stream_info info); + /** + * The index of the stream the decoder is attached to. + */ + int stream_index; -/*Reads a package from an opened media file.*/ -extern lp_ac_package CALL_CONVT ac_read_package(lp_ac_instance pacInstance); -/*Frees a package that has been read.*/ -extern void CALL_CONVT ac_free_package(lp_ac_package pPackage); + /** + * Pointer to the buffer which contains the data. + */ + uint8_t *pBuffer; -extern lp_ac_decoder CALL_CONVT ac_create_audio_decoder(lp_ac_instance pacInstance); -extern lp_ac_decoder CALL_CONVT ac_create_video_decoder(lp_ac_instance pacInstance); -/*Frees an created decoder.*/ -extern void CALL_CONVT ac_free_decoder(lp_ac_decoder pDecoder); -/*Decodes a package using the specified decoder. The decodec data is stored in the - "buffer" property of the decoder.*/ -extern int CALL_CONVT ac_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder); -extern int CALL_CONVT ac_drop_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder); + /** + * Size of the data in the buffer. + */ + int buffer_size; +} ac_decoder; + +typedef ac_decoder *lp_ac_decoder; + +/** + * Contains information about an Acinerella package. + */ +typedef struct _ac_package { + /*The stream the package belongs to.*/ + int stream_index; +} ac_package; + +typedef ac_package *lp_ac_package; + +typedef void *lp_ac_proberesult; + +/** + * Callback function used to ask the application to read data. Should return + * the number of bytes read or an value smaller than zero if an error occured. + */ +typedef int (CALL_CONVT *ac_read_callback)(void *sender, uint8_t *buf, + int size); + +/** + * Callback function used to ask the application to seek. + * + * @param sender is the pointer specified in ac_open. + * @param pos is the position to which the stream should be seeked. + * @param whence specifies whether the seeking should be relative to the + * beginning of the file (0, SEEK_SET), relative to the current location (1, + * SEEK_CUR), or relative to the end of the file (2, SEEK_END) + * @return 0 if the function succeeds, -1 on failure. + */ +typedef int64_t (CALL_CONVT *ac_seek_callback)(void *sender, int64_t pos, + int whence); + +/** + * Callback function that is used to notify the application when the data stream + * is opened or closed. For example the file pointer should be resetted to zero + * when the "open" function is called. + */ +typedef int (CALL_CONVT *ac_openclose_callback)(void *sender); + +/** + * Initializes an Acinerella instance. + * + * @return a pointer at an acinerella instance. The instance must be freed using + * ac_free. + */ +EXTERN lp_ac_instance CALL_CONVT ac_init(void); + +/** +* Initializes an Acinerella instance with a specific output format. +* +* @return a pointer at an acinerella instance. The instance must be freed using +* ac_free. +*/ +EXTERN lp_ac_instance CALL_CONVT ac_init_of(ac_output_format outputFormat); + +/** + * Frees a previously created Acinerella instance. + * + * @param pacInstance is the Acinerella instance that should be freed. + */ +EXTERN void CALL_CONVT ac_free(lp_ac_instance pacInstance); + +/** + * Opens a media stream. + * + * @param inst specifies the Acinerella Instance the stream should be opened + * for. + * @param sender specifies a pointer that is sent to all callback functions to + * allow you to do object orientated programming. May be NULL. + * @param open_proc specifies the callback function that is called, when the + * media file is opened. May be NULL. + * @param seek_proc specifies the callback function that is called, when the + * ffmpeg decoder wants to seek in the file. May be NULL. + * @param close_proc specifies the callback function that is called when the + * media file is closed. May be NULL. + * @param proberesult is a pointer at a structure previously returned by + * ac_probe_input_buffer. May be NULL. + */ +EXTERN int CALL_CONVT + ac_open(lp_ac_instance pacInstance, void *sender, + ac_openclose_callback open_proc, ac_read_callback read_proc, + ac_seek_callback seek_proc, ac_openclose_callback close_proc, + lp_ac_proberesult proberesult); + +/** + * Opens a media file. + * + * @param inst specifies the Acinerella Instance the stream should be opened + * for. + * @param file is the name of the file that should be opened. + */ +EXTERN int CALL_CONVT + ac_open_file(lp_ac_instance pacInstance, const char *filename); + +/** + * Closes an opened media file. + */ +EXTERN void CALL_CONVT ac_close(lp_ac_instance pacInstance); + +/** + * Stores information in "pInfo" about stream number "nb". + */ +EXTERN void CALL_CONVT ac_get_stream_info(lp_ac_instance pacInstance, int nb, + lp_ac_stream_info info); + +/** + * Reads a package from an opened media file. + * + * @param pacInstance is the Acinerella instance from which the data should be + * read. + * @return a pointer at a ac_package structure or NULL on failure. The returned + * pointer must be freed with ac_free_package after use. + */ +EXTERN lp_ac_package CALL_CONVT ac_read_package(lp_ac_instance pacInstance); + +/** + * Frees a package that has been read. + * + * @param pPackage is a pointer at the ac_package that should be freed. May be + * NULL in which case no operation is performed. + */ +EXTERN void CALL_CONVT ac_free_package(lp_ac_package pPackage); + +/** + * Creates an decoder for the specified stream number. Returns NULL if no + * decoder could be found. + */ +EXTERN lp_ac_decoder CALL_CONVT + ac_create_decoder(lp_ac_instance pacInstance, int nb); + +/** + * Frees an created decoder. + */ +EXTERN void CALL_CONVT ac_free_decoder(lp_ac_decoder pDecoder); + +/** + * Decodes a package using the specified decoder. The decoded data is stored in + * the "buffer" property of the decoder. + * + * @param pPackage is the package that should be decoded, previously read by the + * ac_read_package method. + * @param pDecoder is the decoder instance that should be used to decode the + * package -- use the stream index stored in the package to determine the + * correct decoder. + */ +EXTERN int CALL_CONVT + ac_decode_package(lp_ac_package pPackage, lp_ac_decoder pDecoder); + +/** +* Decodes a package using the specified decoder and skips it. Returns true if a frame was skiped. +* +* @param pPackage is the package that should be decoded, previously read by the +* ac_read_package method. +* @param pDecoder is the decoder instance that should be used to decode the +* package -- use the stream index stored in the package to determine the +* correct decoder. +*/ +EXTERN int CALL_CONVT + ac_skip_package(lp_ac_package pPackage, lp_ac_decoder pDecoder); + +/** +* Decodes a packages using the specified decoder and skips num frames. Returns true if num frames where skiped. +* +* @param pacInstance is the Acinerella instance from which the data should be +* read. +* @param pDecoder is the decoder instance that should be used to decode the +* package -- use the stream index stored in the package to determine the +* correct decoder. +* @num number of frames to skip. +*/ +EXTERN int CALL_CONVT + ac_skip_frames(lp_ac_instance pacInstance, lp_ac_decoder pDecoder, int num); + +/** +* Decodes a video frame using the specified decoder and strores the result in the decoder. Returns true if a frame cloud be decoded. +* +* @param pacInstance is the Acinerella instance from which the data should be +* read. +* @param pDecoder is the decoder instance that should be used to decode the +* package -- use the stream index stored in the package to determine the +* correct decoder. +*/ +EXTERN int CALL_CONVT + ac_get_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder); + +/** +* Decodes a audio frame using the specified decoder and strores the result in the decoder. Returns true if a frame cloud be decoded. +* +* @param pacInstance is the Acinerella instance from which the data should be +* read. +* @param pDecoder is the decoder instance that should be used to decode the +* package -- use the stream index stored in the package to determine the +* correct decoder. +*/ +EXTERN int CALL_CONVT + ac_get_audio_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder); + + +/** + * Seeks to the given target position in the file. The seek funtion is not able + * to seek a single audio/video stream but seeks the whole file forward. The + * stream number paremter (nb) is only used for the timecode reference. + * The parameter "dir" specifies the seek direction: 0 for forward, -1 for + * backward. The target_pos paremeter is in milliseconds. Returns 1 if the + * functions succeded. + */ +EXTERN int CALL_CONVT + ac_seek(lp_ac_decoder pDecoder, int dir, int64_t target_pos); + +/** + * Checks whether the given input buffer contains data that can potentially be + * decoded by Acinerella. If yes, returns a pointer that may be passed to + * ac_open in order to speed up the open process. Otherwise returns NULL. + * + * @param buf is a pointer to the buffer in which the data is stored. + * @param bufsize is the size of the buffer. + * @param filename is the name of the file the buffer originated from. May be + * empty or NULL. + * @param score_max is set to the maximum of the previous value of score_max + * and an internal score value. + * @return either a pointer at an internal "probe result" or NULL if the buffer + * contains no decodeable data. + */ +EXTERN lp_ac_proberesult CALL_CONVT + ac_probe_input_buffer(uint8_t *buf, int bufsize, char *filename, + int *score_max); + +#endif /* _ACINERELLA_H_ */ -extern int CALL_CONVT ac_get_audio_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder); -extern int CALL_CONVT ac_get_frame(lp_ac_instance pacInstance, lp_ac_decoder pDecoder); -extern int CALL_CONVT ac_skip_frames(lp_ac_instance pacInstance, lp_ac_decoder pDecoder, int num); - -/*Seeks to the given target position in the file. The seek funtion is not able to seek a single audio/video stream -but seeks the whole file forward. The stream number paremter (nb) is only used for the timecode reference. -The parameter "dir" specifies the seek direction: 0 for forward, -1 for backward. -The target_pos paremeter is in milliseconds. Returns 1 if the functions succeded.*/ -extern int CALL_CONVT ac_seek(lp_ac_decoder pDecoder, int dir, int64_t target_pos); -#endif /*VIDEOPLAY_H*/ diff --git a/Vocaluxe/Linux/Build/PreBuildEvent.sh b/Vocaluxe/Linux/Build/PreBuildEvent.sh deleted file mode 100755 index 9fe7bd5b..00000000 --- a/Vocaluxe/Linux/Build/PreBuildEvent.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -PROJECT=$1 -cd $PROJECT -sed -i -e s/GITVERSION/$(git describe --long)/ $PROJECT/Properties/AssemblyInfo.cs -shortv=$(git describe --abbrev=0 | sed -e 's/alpha/0/' -e 's/beta/1/' -e 's/rc/2/') -sed -i -e s/SHORTVERSION/${shortv}/ $PROJECT/Properties/AssemblyInfo.cs diff --git a/Vocaluxe/Program.cs b/Vocaluxe/Program.cs index 4da68bf2..d18660db 100644 --- a/Vocaluxe/Program.cs +++ b/Vocaluxe/Program.cs @@ -92,6 +92,9 @@ namespace Vocaluxe try { + // Create data folder + Directory.CreateDirectory(CSettings.DataFolder); + // Init Log CLog.Init(); diff --git a/Vocaluxe/Properties/AssemblyInfo.cs b/Vocaluxe/Properties/AssemblyInfo.cs index 4cde4f89..5ab36484 100644 --- a/Vocaluxe/Properties/AssemblyInfo.cs +++ b/Vocaluxe/Properties/AssemblyInfo.cs @@ -22,12 +22,12 @@ using System.Runtime.InteropServices; // Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, // die mit einer Assembly verknüpft sind. -[assembly: AssemblyTitle("Vocaluxe")] +[assembly: AssemblyTitle("FULLVERSION")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("Vocaluxe")] -[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyCopyright("Copyright © 2017")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] diff --git a/Vocaluxe/Screens/CScreenHighscore.cs b/Vocaluxe/Screens/CScreenHighscore.cs index 182e68ed..0e6a746f 100644 --- a/Vocaluxe/Screens/CScreenHighscore.cs +++ b/Vocaluxe/Screens/CScreenHighscore.cs @@ -285,7 +285,7 @@ namespace Vocaluxe.Screens private void _ChangePos(int num) { - if (_Scores[_Round].Count == 0) + if (_Scores[_Round].Count == 0 || _Scores[_Round].Count <= _NumEntrys) _Pos = 0; else { diff --git a/Vocaluxe/Screens/CScreenMain.cs b/Vocaluxe/Screens/CScreenMain.cs index a884c016..e1f2a424 100644 --- a/Vocaluxe/Screens/CScreenMain.cs +++ b/Vocaluxe/Screens/CScreenMain.cs @@ -57,6 +57,7 @@ namespace Vocaluxe.Screens _Texts[_TextRelease].Visible = true; _Statics[_StaticWarningProfiles].Visible = false; _Texts[_TextWarningProfiles].Visible = false; + _SelectElement(_Buttons[_ButtonSing]); } public override bool HandleInput(SKeyEvent keyEvent) @@ -105,6 +106,10 @@ namespace Vocaluxe.Screens return false; break; + + case Keys.Escape: + _SelectElement(_Buttons[_ButtonExit]); + break; } } return true; diff --git a/Vocaluxe/Screens/CScreenOptionsGame.cs b/Vocaluxe/Screens/CScreenOptionsGame.cs index 485ce2b0..72a7d4e6 100644 --- a/Vocaluxe/Screens/CScreenOptionsGame.cs +++ b/Vocaluxe/Screens/CScreenOptionsGame.cs @@ -80,6 +80,7 @@ namespace Vocaluxe.Screens case Keys.S: CParty.SetNormalGameMode(); + _SaveConfig(); CGraphics.FadeTo(EScreen.Song); break; diff --git a/Vocaluxe/Screens/CScreenOptionsLyrics.cs b/Vocaluxe/Screens/CScreenOptionsLyrics.cs index da4a608d..49c68929 100644 --- a/Vocaluxe/Screens/CScreenOptionsLyrics.cs +++ b/Vocaluxe/Screens/CScreenOptionsLyrics.cs @@ -67,6 +67,7 @@ namespace Vocaluxe.Screens case Keys.S: CParty.SetNormalGameMode(); + _SaveConfig(); CGraphics.FadeTo(EScreen.Song); break; diff --git a/Vocaluxe/Screens/CScreenOptionsRecord.cs b/Vocaluxe/Screens/CScreenOptionsRecord.cs index da838eda..bac267a9 100644 --- a/Vocaluxe/Screens/CScreenOptionsRecord.cs +++ b/Vocaluxe/Screens/CScreenOptionsRecord.cs @@ -112,6 +112,7 @@ namespace Vocaluxe.Screens case Keys.S: CParty.SetNormalGameMode(); + _SaveMicConfig(); CGraphics.FadeTo(EScreen.Song); break; diff --git a/Vocaluxe/Screens/CScreenOptionsSound.cs b/Vocaluxe/Screens/CScreenOptionsSound.cs index c3d47d1f..cf6afcec 100644 --- a/Vocaluxe/Screens/CScreenOptionsSound.cs +++ b/Vocaluxe/Screens/CScreenOptionsSound.cs @@ -89,6 +89,7 @@ namespace Vocaluxe.Screens case Keys.S: CParty.SetNormalGameMode(); + _SaveConfig(); CGraphics.FadeTo(EScreen.Song); break; diff --git a/Vocaluxe/Screens/CScreenOptionsTheme.cs b/Vocaluxe/Screens/CScreenOptionsTheme.cs index 6723a305..7beb9a15 100644 --- a/Vocaluxe/Screens/CScreenOptionsTheme.cs +++ b/Vocaluxe/Screens/CScreenOptionsTheme.cs @@ -92,6 +92,7 @@ namespace Vocaluxe.Screens case Keys.S: CParty.SetNormalGameMode(); + _SaveConfig(); CGraphics.FadeTo(EScreen.Song); break; diff --git a/Vocaluxe/Screens/CScreenOptionsVideo.cs b/Vocaluxe/Screens/CScreenOptionsVideo.cs index d8ff7710..8c33e722 100644 --- a/Vocaluxe/Screens/CScreenOptionsVideo.cs +++ b/Vocaluxe/Screens/CScreenOptionsVideo.cs @@ -95,6 +95,7 @@ namespace Vocaluxe.Screens case Keys.S: CParty.SetNormalGameMode(); + _SaveConfig(); CGraphics.FadeTo(EScreen.Song); break; diff --git a/Vocaluxe/Screens/CScreenOptionsVideoAdjustments.cs b/Vocaluxe/Screens/CScreenOptionsVideoAdjustments.cs index 0ad53c54..b030b14e 100644 --- a/Vocaluxe/Screens/CScreenOptionsVideoAdjustments.cs +++ b/Vocaluxe/Screens/CScreenOptionsVideoAdjustments.cs @@ -56,6 +56,7 @@ namespace Vocaluxe.Screens case Keys.S: CParty.SetNormalGameMode(); + _SaveConfig(); CGraphics.FadeTo(EScreen.Song); break; diff --git a/Vocaluxe/Screens/CScreenProfiles.cs b/Vocaluxe/Screens/CScreenProfiles.cs index 44196e34..f98a3c2e 100644 --- a/Vocaluxe/Screens/CScreenProfiles.cs +++ b/Vocaluxe/Screens/CScreenProfiles.cs @@ -319,6 +319,8 @@ namespace Vocaluxe.Screens _Buttons[_ButtonDiscardSnapshot].Visible = false; _Buttons[_ButtonTakeSnapshot].Visible = false; _Buttons[_ButtonWebcam].Visible = false; + + _SelectElement(_Buttons[_ButtonSave]); } else { @@ -330,6 +332,8 @@ namespace Vocaluxe.Screens _Buttons[_ButtonDiscardSnapshot].Visible = true; _Buttons[_ButtonTakeSnapshot].Visible = false; _Buttons[_ButtonWebcam].Visible = false; + + _SelectElement(_Buttons[_ButtonSaveSnapshot]); } } @@ -341,6 +345,8 @@ namespace Vocaluxe.Screens _Buttons[_ButtonDiscardSnapshot].Visible = false; _Buttons[_ButtonTakeSnapshot].Visible = false; _Buttons[_ButtonWebcam].Visible = CWebcam.IsDeviceAvailable(); + + _SelectElement(_Buttons[_ButtonWebcam]); } private void _OnSaveSnapshot() @@ -359,6 +365,8 @@ namespace Vocaluxe.Screens int id = CProfiles.NewAvatar(file); CProfiles.SetAvatar(_SelectSlides[_SelectSlideProfiles].SelectedTag, id); _LoadAvatars(false); + + _SelectElement(_Buttons[_ButtonSave]); } private void _OnWebcam() @@ -374,6 +382,8 @@ namespace Vocaluxe.Screens _Buttons[_ButtonDiscardSnapshot].Visible = false; _Buttons[_ButtonTakeSnapshot].Visible = true; _Buttons[_ButtonWebcam].Visible = false; + + _SelectElement(_Buttons[_ButtonTakeSnapshot]); } private void _NewProfile() diff --git a/Vocaluxe/Screens/CScreenSong.cs b/Vocaluxe/Screens/CScreenSong.cs index c14037ba..ad8c73d0 100644 --- a/Vocaluxe/Screens/CScreenSong.cs +++ b/Vocaluxe/Screens/CScreenSong.cs @@ -172,7 +172,12 @@ namespace Vocaluxe.Screens { keyEvent.Handled = _Playlist.HandleInput(keyEvent); if (keyEvent.Handled) + { + //Check if playlist was closed and song menu needed to be resized + if (!_Playlist.Visible) + _SongMenu.SmallView = false; return true; + } if (!keyEvent.KeyPressed && keyEvent.Key == Keys.Escape) { _ClosePlaylist(); @@ -362,7 +367,10 @@ namespace Vocaluxe.Screens { if (CSongs.IsInCategory) _SongMenu.SetSelectedSong(CSongs.GetRandomSong()); - else + } + else if (_Buttons[_ButtonOptionsRandomCategory].Selected) + { + if (!CSongs.IsInCategory) _SongMenu.SetSelectedCategory(CSongs.GetRandomCategory()); } else if (_Buttons[_ButtonOptionsSingAll].Selected) @@ -411,7 +419,12 @@ namespace Vocaluxe.Screens _SongMenu.Selected = false; _ToggleSongOptions(ESongOptionsView.None); if (_Playlist.HandleMouse(mouseEvent)) + { + //Check if playlist was closed and song menu needed to be resized + if (!_Playlist.Visible) + _SongMenu.SmallView = false; return true; + } } else if (CHelper.IsInBounds(_SongMenu.Rect, mouseEvent)) { @@ -1261,6 +1274,8 @@ namespace Vocaluxe.Screens { _SongMenu.SmallView = true; _Playlist.Visible = true; + _SelectElement(_Playlist); + _ToggleSongOptions(ESongOptionsView.None); } } diff --git a/Vocaluxe/Vocaluxe.csproj b/Vocaluxe/Vocaluxe.csproj index ef349b8e..248e7a46 100644 --- a/Vocaluxe/Vocaluxe.csproj +++ b/Vocaluxe/Vocaluxe.csproj @@ -477,15 +477,14 @@ - xcopy /E /D /Y "$(ProjectDir)\Website" "$(SolutionDir)\PhoneGap" -powershell -command "if($Env:GIT_VERSION_TAG) {$version = $Env:GIT_VERSION_TAG;} else {$version = git describe --long;}(Get-Content -Encoding UTF8 '$(ProjectDir)..\Output\Website\js\main.js') | Foreach-Object {$_ -replace '(?<=var *matchingServerVersion * = *\")\w*(?=\" *;)', "$version"} | Set-Content -Encoding UTF8 '$(ProjectDir)..\Output\Website\js\main.js'" -powershell -command "(Get-Content -Encoding UTF8 '$(ProjectDir)Properties\AssemblyInfo.cs') | Foreach-Object {$_ -replace '(?<=AssemblyInformationalVersion\(\").*(?=\")', 'GITVERSION'} | Foreach-Object {$_ -replace '(?<=(AssemblyVersion|AssemblyFileVersion)\(\").*(?=\")', 'SHORTVERSION'} | Set-Content -Encoding UTF8 '$(ProjectDir)Properties\AssemblyInfo.cs' " + xcopy /E /D /Y "$(ProjectDir)\Website" "$(SolutionDir)\PhoneGap" + powershell -ExecutionPolicy Bypass -File $(SolutionDir)\.build\winPostBuild.ps1 $(ProjectDir) cp -ruT "$(ProjectDir)Website" "$(SolutionDir)/PhoneGap" - $(ProjectDir)Linux/Build/PostBuildEvent.sh $(ProjectDir) + $(SolutionDir)/.build/linuxPostBuildEvent.sh $(ProjectDir) - powershell -command " if($Env:GIT_VERSION_TAG) {$version = $Env:GIT_VERSION_TAG;} else {$version = git describe --long;} (Get-Content -Encoding UTF8 '$(ProjectDir)Properties\AssemblyInfo.cs') | Foreach-Object {$_ -replace '(?<=AssemblyInformationalVersion\(\").*(?=\")', $version} | Foreach-Object {$_ -replace '(?<=(AssemblyVersion|AssemblyFileVersion)\(\").*(?=\")', $version.Split('-')[0].replace('alpha','0').replace('beta','1').replace('rc','2')} | Foreach-Object {$_ -replace '(?<=AssemblyCopyright\(\".*)[0-9]+(?=\")', (Get-Date).Year} | Set-Content -Encoding UTF8 '$(ProjectDir)Properties\AssemblyInfo.cs' " - $(ProjectDir)Linux/Build/PreBuildEvent.sh $(ProjectDir) + powershell -ExecutionPolicy Bypass -File $(SolutionDir)\.build\winPreBuild.ps1 $(ProjectDir) $(Platform) + $(SolutionDir)/.build/linuxPreBuildEvent.sh $(ProjectDir) $(Platform)