Update HEVC converter and NVEncoder
This commit is contained in:
parent
2f9fdc681d
commit
3dc94cbebe
10
README.md
10
README.md
@ -1,5 +1,4 @@
|
|||||||
|
# Automated HEVC-Video-Converter
|
||||||
# Automated HEVC-Video-Converter 1.0
|
|
||||||
|
|
||||||
A PowerShell script for converting video to the HEVC video format using GPU hardware acceleration with NVEnc for Windows.
|
A PowerShell script for converting video to the HEVC video format using GPU hardware acceleration with NVEnc for Windows.
|
||||||
|
|
||||||
@ -20,7 +19,6 @@ _Results vary and depend on the input video's format, bitrate etc._
|
|||||||
- Recent nvidia graphics card ([see: NVENC support matrix](https://developer.nvidia.com/video-encode-decode-gpu-support-matrix))
|
- Recent nvidia graphics card ([see: NVENC support matrix](https://developer.nvidia.com/video-encode-decode-gpu-support-matrix))
|
||||||
- Latest nvidia graphics drivers
|
- Latest nvidia graphics drivers
|
||||||
|
|
||||||
|
|
||||||
## Encoding
|
## Encoding
|
||||||
|
|
||||||
During encoding (conversion), high **CPU** and **GPU** usage is normal. Make sure that you only run the script if no other graphics processes are running on the computer. (Example computer games)
|
During encoding (conversion), high **CPU** and **GPU** usage is normal. Make sure that you only run the script if no other graphics processes are running on the computer. (Example computer games)
|
||||||
@ -30,7 +28,6 @@ After conversion, a test of the new video file is performed to ensure its integr
|
|||||||
If this test is successful, the old file is deleted.
|
If this test is successful, the old file is deleted.
|
||||||
If not, the failed conversion file is deleted and logged.
|
If not, the failed conversion file is deleted and logged.
|
||||||
|
|
||||||
|
|
||||||
## Script Usage
|
## Script Usage
|
||||||
|
|
||||||
1. Clone this repository on your computer
|
1. Clone this repository on your computer
|
||||||
@ -39,7 +36,6 @@ If not, the failed conversion file is deleted and logged.
|
|||||||
4. Edit the $videoPath variable in the PowerShell file to point to the folder of your "video files" to convert. (**ATTENTION: The ending-slash must be preserved in the path specification!**)
|
4. Edit the $videoPath variable in the PowerShell file to point to the folder of your "video files" to convert. (**ATTENTION: The ending-slash must be preserved in the path specification!**)
|
||||||
5. Execute **convert_Videos.ps1** to convert the video files under the specified path to HEVC.
|
5. Execute **convert_Videos.ps1** to convert the video files under the specified path to HEVC.
|
||||||
|
|
||||||
|
## Extra Content (\_extras folder)
|
||||||
|
|
||||||
## Extra Content (_extras folder)
|
- **manually_review_videos.ps1** - Redoes the review process using the "review_needed.log" -> before useing set the "$logFolderName" variable in file.
|
||||||
|
|
||||||
* **manually_review_videos.ps1** - Redoes the review process using the "review_needed.log" -> before useing set the "$logFolderName" variable in file.
|
|
||||||
|
@ -10,7 +10,7 @@ $videoPath = 'M:\2_serien\_main.series'
|
|||||||
|
|
||||||
#-----------------------------------------------------------------------
|
#-----------------------------------------------------------------------
|
||||||
# HEVC profiles: main, main10, main444
|
# HEVC profiles: main, main10, main444
|
||||||
$profile = 'main10'
|
$hevc_profile = 'main10'
|
||||||
$forceReviewAll = $false # If set to $true all failed conversions are reviewed even those that are obviously corrupt.
|
$forceReviewAll = $false # If set to $true all failed conversions are reviewed even those that are obviously corrupt.
|
||||||
|
|
||||||
$NVEncoder = "$PSScriptRoot\encoder\NVEncC64.exe"
|
$NVEncoder = "$PSScriptRoot\encoder\NVEncC64.exe"
|
||||||
@ -20,11 +20,10 @@ $reviewPlayer = "C:\Program Files\VideoLAN\VLC\vlc.exe"
|
|||||||
#############################################################################################################
|
#############################################################################################################
|
||||||
# Testing and conversion preparations #
|
# Testing and conversion preparations #
|
||||||
#############################################################################################################
|
#############################################################################################################
|
||||||
if(!(Test-Path $NVEncoder -PathType leaf))
|
if (!(Test-Path $NVEncoder -PathType leaf)) {
|
||||||
{
|
Write-Host "NVEncC64.exe not found, please check path in `"$NVEncoder`"." -ForegroundColor Yellow
|
||||||
Write-Host "NVEncC64.exe not found, please check path in `"$NVEncoder`"." -ForegroundColor Yellow
|
|
||||||
Read-Host -Prompt "Press Enter to exit"
|
Read-Host -Prompt "Press Enter to exit"
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get video list from provided path:
|
# Get video list from provided path:
|
||||||
@ -40,17 +39,15 @@ $failedVideos = 0
|
|||||||
$logFolderName = $((Get-Date).tostring("yyyy-MM-dd") + ' - [run started at ' + (Get-Date).tostring("HH-mm") + ']')
|
$logFolderName = $((Get-Date).tostring("yyyy-MM-dd") + ' - [run started at ' + (Get-Date).tostring("HH-mm") + ']')
|
||||||
$count = $videos.Count
|
$count = $videos.Count
|
||||||
|
|
||||||
if($videos.Count -lt 1)
|
if ($videos.Count -lt 1) {
|
||||||
{
|
Write-Host "No videos found in: $videoPath" -ForegroundColor Red
|
||||||
Write-Host "No videos found in: $videoPath" -ForegroundColor Red
|
Read-Host -Prompt "Press Enter to exit"
|
||||||
Read-Host -Prompt "Press Enter to exit"
|
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
# Log write function:
|
# Log write function:
|
||||||
Function LogWrite
|
Function LogWrite {
|
||||||
{
|
Param ([string]$logstring)
|
||||||
Param ([string]$logstring)
|
Add-content -LiteralPath $Logfile -value $logstring
|
||||||
Add-content -LiteralPath $Logfile -value $logstring
|
|
||||||
}
|
}
|
||||||
# Create new log directory:
|
# Create new log directory:
|
||||||
New-Item -itemType Directory -Path $PSScriptRoot\logs\ -Name $logFolderName > $null
|
New-Item -itemType Directory -Path $PSScriptRoot\logs\ -Name $logFolderName > $null
|
||||||
@ -71,30 +68,28 @@ Write-Host
|
|||||||
Write-Host
|
Write-Host
|
||||||
Write-Host "------------------------------------------------------------------------------------------------"
|
Write-Host "------------------------------------------------------------------------------------------------"
|
||||||
|
|
||||||
foreach($video in $videos)
|
foreach ($video in $videos) {
|
||||||
{
|
|
||||||
|
|
||||||
$video = $video.Replace("`"", "")
|
$video = $video.Replace("`"", "")
|
||||||
$inputFile = $videoPath + "\" + $video
|
$inputFile = $videoPath + "\" + $video
|
||||||
|
|
||||||
# Pre-file-check if "HEVC" exist in filename skip filechecking:
|
# Pre-file-check if "HEVC" exist in filename skip filechecking:
|
||||||
if ($video -match "HEVC")
|
if ($video -match "HEVC") {
|
||||||
{
|
|
||||||
$codec = "HEVC"
|
$codec = "HEVC"
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
# Get and check File info for codec, if it's already HEVC: - JSON query: (['media']['track'][1]['Format'])
|
# Get and check File info for codec, if it's already HEVC: - JSON query: (['media']['track'][1]['Format'])
|
||||||
$fileDetails = cmd /c $fileTester $inputFile --Output=JSON | ConvertFrom-Json
|
$fileDetails = cmd /c $fileTester $inputFile --Output=JSON | ConvertFrom-Json
|
||||||
$codec = $fileDetails.media.track[1].Format
|
$codec = $fileDetails.media.track[1].Format
|
||||||
}
|
}
|
||||||
|
|
||||||
# If not already HEVC, convert video using NVEncC64:
|
# If not already HEVC, convert video using NVEncC64:
|
||||||
if($codec -ne "HEVC")
|
if ($codec -ne "HEVC") {
|
||||||
{
|
|
||||||
# Configure new file naming:
|
# Configure new file naming:
|
||||||
if ($video -match "264")
|
if ($video -match "264") {
|
||||||
{
|
|
||||||
$outputFile = $videoPath + "\" + $video.Replace("264", "265")
|
$outputFile = $videoPath + "\" + $video.Replace("264", "265")
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
$outputFile = $videoPath + "\" + $video.Insert(($video.Length - 4), '-HEVC')
|
$outputFile = $videoPath + "\" + $video.Insert(($video.Length - 4), '-HEVC')
|
||||||
}
|
}
|
||||||
Write-Host "Analyzing video ($videoID of $count), starting convertion of number: $($convertedVideos + 1) please wait.." -ForegroundColor Magenta
|
Write-Host "Analyzing video ($videoID of $count), starting convertion of number: $($convertedVideos + 1) please wait.." -ForegroundColor Magenta
|
||||||
@ -102,7 +97,7 @@ foreach($video in $videos)
|
|||||||
Write-Host
|
Write-Host
|
||||||
|
|
||||||
# If the Subtitles should not be copied, delete the "--sub-copy 1,2" argument.
|
# If the Subtitles should not be copied, delete the "--sub-copy 1,2" argument.
|
||||||
$arguments = "--input `"$inputFile`" --codec hevc --audio-copy 1,2,3,4 --sub-copy 1,2,3,4 --profile $profile --output `"$outputFile`""
|
$arguments = "--input `"$inputFile`" --codec hevc --audio-copy 1,2,3,4 --sub-copy 1,2,3,4 --profile $hevc_profile --output `"$outputFile`""
|
||||||
|
|
||||||
Start-Process $NVEncoder -ArgumentList $arguments -WindowStyle Minimized
|
Start-Process $NVEncoder -ArgumentList $arguments -WindowStyle Minimized
|
||||||
|
|
||||||
@ -115,7 +110,7 @@ foreach($video in $videos)
|
|||||||
# $noOfCores.Sum = $noOfCores.Sum - 1
|
# $noOfCores.Sum = $noOfCores.Sum - 1
|
||||||
# [math]::Pow(2,$($noOfCores).Sum) - 1
|
# [math]::Pow(2,$($noOfCores).Sum) - 1
|
||||||
#
|
#
|
||||||
$process = Get-Process $processName; $process.ProcessorAffinity=7
|
$process = Get-Process $processName; $process.ProcessorAffinity = 7
|
||||||
Start-Sleep -Seconds 2
|
Start-Sleep -Seconds 2
|
||||||
# Sets priorty to High
|
# Sets priorty to High
|
||||||
# Values: High, AboveNormal, Normal, BelowNormal, Low
|
# Values: High, AboveNormal, Normal, BelowNormal, Low
|
||||||
@ -127,10 +122,9 @@ foreach($video in $videos)
|
|||||||
Wait-Process -Id $processID
|
Wait-Process -Id $processID
|
||||||
|
|
||||||
|
|
||||||
if(Test-Path -LiteralPath $outputFile)
|
if (Test-Path -LiteralPath $outputFile)
|
||||||
# Specifies a path to be tested. Unlike Path, the value of the LiteralPath parameter is used exactly as it is typed.
|
{ # Specifies a path to be tested. Unlike Path, the value of the LiteralPath parameter is used exactly as it is typed.
|
||||||
#No characters are interpreted as wildcard characters.
|
#No characters are interpreted as wildcard characters.
|
||||||
{
|
|
||||||
Write-Host "CONVERSION DONE! FILE: `"$outputFile`" FOUND" -ForegroundColor Yellow
|
Write-Host "CONVERSION DONE! FILE: `"$outputFile`" FOUND" -ForegroundColor Yellow
|
||||||
Start-Sleep -Seconds 4
|
Start-Sleep -Seconds 4
|
||||||
|
|
||||||
@ -138,15 +132,14 @@ foreach($video in $videos)
|
|||||||
$fileDetails_new = cmd /c $fileTester $outputFile --Output=JSON | ConvertFrom-Json
|
$fileDetails_new = cmd /c $fileTester $outputFile --Output=JSON | ConvertFrom-Json
|
||||||
|
|
||||||
# This code gets the duration and splits it in two parts, only the part before the "." is needed:
|
# This code gets the duration and splits it in two parts, only the part before the "." is needed:
|
||||||
$StreamSize_old,$notused = $($fileDetails.media.track[0].Duration).split('.')
|
$StreamSize_old, $notused = $($fileDetails.media.track[0].Duration).split('.')
|
||||||
$StreamSize_new,$notused = $($fileDetails_new.media.track[0].Duration).split('.')
|
$StreamSize_new, $notused = $($fileDetails_new.media.track[0].Duration).split('.')
|
||||||
|
|
||||||
Write-Host
|
Write-Host
|
||||||
Write-Host "Old Duration was: $StreamSize_old `nnew Duration is: $StreamSize_new" -ForegroundColor White
|
Write-Host "Old Duration was: $StreamSize_old `nnew Duration is: $StreamSize_new" -ForegroundColor White
|
||||||
Write-Host
|
Write-Host
|
||||||
|
|
||||||
if ($StreamSize_new -eq $StreamSize_old)
|
if ($StreamSize_new -eq $StreamSize_old) {
|
||||||
{
|
|
||||||
# Delete old video File!
|
# Delete old video File!
|
||||||
Write-Host "Conversion Successful! - Deleting old file.."
|
Write-Host "Conversion Successful! - Deleting old file.."
|
||||||
Write-Host
|
Write-Host
|
||||||
@ -155,10 +148,9 @@ foreach($video in $videos)
|
|||||||
$convertedVideos = $convertedVideos + 1
|
$convertedVideos = $convertedVideos + 1
|
||||||
$Logfile = "$PSScriptRoot\logs\$logFolderName\successfully_converted.log"
|
$Logfile = "$PSScriptRoot\logs\$logFolderName\successfully_converted.log"
|
||||||
LogWrite "$outputFile"
|
LogWrite "$outputFile"
|
||||||
} else
|
}
|
||||||
{
|
else {
|
||||||
if (($StreamSize_new -eq $($StreamSize_old - 1)) -or ($($StreamSize_new - 1) -eq $StreamSize_old))
|
if (($StreamSize_new -eq $($StreamSize_old - 1)) -or ($($StreamSize_new - 1) -eq $StreamSize_old)) {
|
||||||
{
|
|
||||||
# Newly converted file does not match exactly the old duration. But diffrence its not more than 1 sec!
|
# Newly converted file does not match exactly the old duration. But diffrence its not more than 1 sec!
|
||||||
Write-Host "Conversion Done! - Streamsize is not exactly the same. But still OK - Ignoring!"
|
Write-Host "Conversion Done! - Streamsize is not exactly the same. But still OK - Ignoring!"
|
||||||
Write-Host
|
Write-Host
|
||||||
@ -168,8 +160,8 @@ foreach($video in $videos)
|
|||||||
$Logfile = "$PSScriptRoot\logs\$logFolderName\successfully_converted.log"
|
$Logfile = "$PSScriptRoot\logs\$logFolderName\successfully_converted.log"
|
||||||
LogWrite "$outputFile"
|
LogWrite "$outputFile"
|
||||||
|
|
||||||
} elseif (($StreamSize_new -ge $($StreamSize_old - 20)) -or ($($StreamSize_new - 20) -ge $StreamSize_old))
|
}
|
||||||
{
|
elseif (($StreamSize_new -ge $($StreamSize_old - 20)) -or ($($StreamSize_new - 20) -ge $StreamSize_old)) {
|
||||||
# New converted file has been converted but with up to max 20 seconds deviation!
|
# New converted file has been converted but with up to max 20 seconds deviation!
|
||||||
Write-Host "Conversion Done! - But streamsize is not the same. - Please review!"
|
Write-Host "Conversion Done! - But streamsize is not the same. - Please review!"
|
||||||
Write-Host
|
Write-Host
|
||||||
@ -180,10 +172,9 @@ foreach($video in $videos)
|
|||||||
LogWrite "$inputFile,$outputFile"
|
LogWrite "$inputFile,$outputFile"
|
||||||
|
|
||||||
|
|
||||||
} else
|
}
|
||||||
{
|
else {
|
||||||
if ($forceReviewAll)
|
if ($forceReviewAll) {
|
||||||
{
|
|
||||||
# Mark probably corrupted file for review
|
# Mark probably corrupted file for review
|
||||||
Write-Host "Conversion Failed! - Marked for review! because it is desired."
|
Write-Host "Conversion Failed! - Marked for review! because it is desired."
|
||||||
Write-Host
|
Write-Host
|
||||||
@ -192,8 +183,8 @@ foreach($video in $videos)
|
|||||||
$convertedVideos = $convertedVideos + 1
|
$convertedVideos = $convertedVideos + 1
|
||||||
$Logfile = "$PSScriptRoot\logs\$logFolderName\review_needed.log"
|
$Logfile = "$PSScriptRoot\logs\$logFolderName\review_needed.log"
|
||||||
LogWrite "$inputFile,$outputFile"
|
LogWrite "$inputFile,$outputFile"
|
||||||
} else
|
}
|
||||||
{
|
else {
|
||||||
# Delete obviously corrupt File!
|
# Delete obviously corrupt File!
|
||||||
Write-Host "Conversion Failded! - Deleting new converted file.." -ForegroundColor Red
|
Write-Host "Conversion Failded! - Deleting new converted file.." -ForegroundColor Red
|
||||||
Write-Host
|
Write-Host
|
||||||
@ -207,8 +198,8 @@ foreach($video in $videos)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
}
|
||||||
{
|
else {
|
||||||
# Alert if video doesn't need conversion:
|
# Alert if video doesn't need conversion:
|
||||||
Write-Host "Analyzing video ($videoID of $count) - skip" -ForegroundColor Magenta
|
Write-Host "Analyzing video ($videoID of $count) - skip" -ForegroundColor Magenta
|
||||||
Write-Host "$video is already in correct format!" -ForegroundColor Green
|
Write-Host "$video is already in correct format!" -ForegroundColor Green
|
||||||
@ -231,8 +222,7 @@ foreach($video in $videos)
|
|||||||
#############################################################################################################
|
#############################################################################################################
|
||||||
# Evaluation part of the conversion script #
|
# Evaluation part of the conversion script #
|
||||||
#############################################################################################################
|
#############################################################################################################
|
||||||
if ($review)
|
if ($review) {
|
||||||
{
|
|
||||||
$reviewFiles = Get-content -LiteralPath "$PSScriptRoot\logs\$logFolderName\review_needed.log" | Measure-Object –Line
|
$reviewFiles = Get-content -LiteralPath "$PSScriptRoot\logs\$logFolderName\review_needed.log" | Measure-Object –Line
|
||||||
$ReviewCount = $reviewFiles.Lines
|
$ReviewCount = $reviewFiles.Lines
|
||||||
|
|
||||||
@ -242,9 +232,8 @@ if ($review)
|
|||||||
Write-Host "################################################################################################"
|
Write-Host "################################################################################################"
|
||||||
$review_count = 1
|
$review_count = 1
|
||||||
|
|
||||||
foreach($review_pair in Get-Content -LiteralPath "$PSScriptRoot\logs\$logFolderName\review_needed.log")
|
foreach ($review_pair in Get-Content -LiteralPath "$PSScriptRoot\logs\$logFolderName\review_needed.log") {
|
||||||
{
|
$oldFile, $newFile = $review_pair.split(',')
|
||||||
$oldFile,$newFile = $review_pair.split(',')
|
|
||||||
Write-Host "Playing $review_count converted file: $newFile"
|
Write-Host "Playing $review_count converted file: $newFile"
|
||||||
Write-Host
|
Write-Host
|
||||||
|
|
||||||
@ -261,12 +250,11 @@ if ($review)
|
|||||||
$response = Read-Host -Prompt $msg
|
$response = Read-Host -Prompt $msg
|
||||||
} until (($response -eq 'n') -or ($response -eq 'y'))
|
} until (($response -eq 'n') -or ($response -eq 'y'))
|
||||||
|
|
||||||
if ($response -eq 'y')
|
if ($response -eq 'y') {
|
||||||
{
|
|
||||||
Write-Host "delete old file, keep newly converted.."
|
Write-Host "delete old file, keep newly converted.."
|
||||||
$to_delete = $oldFile
|
$to_delete = $oldFile
|
||||||
} else
|
}
|
||||||
{
|
else {
|
||||||
Write-Host "delete newly converted, keep old file"
|
Write-Host "delete newly converted, keep old file"
|
||||||
$to_delete = $newFile
|
$to_delete = $newFile
|
||||||
$failedVideos = $failedVideos + 1
|
$failedVideos = $failedVideos + 1
|
||||||
@ -281,16 +269,14 @@ if ($review)
|
|||||||
|
|
||||||
Write-Host "Final calculations are in progress.."
|
Write-Host "Final calculations are in progress.."
|
||||||
$folderSizeInGB2 = "{0:N2} GB" -f ((Get-ChildItem $videoPath -Recurse | Measure-Object -Property Length -Sum -ErrorAction Stop).Sum / 1GB)
|
$folderSizeInGB2 = "{0:N2} GB" -f ((Get-ChildItem $videoPath -Recurse | Measure-Object -Property Length -Sum -ErrorAction Stop).Sum / 1GB)
|
||||||
if($notConvertedVideos -eq 0)
|
if ($notConvertedVideos -eq 0) {
|
||||||
{
|
|
||||||
Write-Host "Finished converted $convertedVideos out of $count videos." -ForegroundColor Green
|
Write-Host "Finished converted $convertedVideos out of $count videos." -ForegroundColor Green
|
||||||
} else
|
}
|
||||||
{
|
else {
|
||||||
if($failedVideos -eq 0)
|
if ($failedVideos -eq 0) {
|
||||||
{
|
|
||||||
Write-Host "Finished converted $convertedVideos out of $count videos. - $notConvertedVideos where not converted because of already correct codec!" -ForegroundColor Green
|
Write-Host "Finished converted $convertedVideos out of $count videos. - $notConvertedVideos where not converted because of already correct codec!" -ForegroundColor Green
|
||||||
} else
|
}
|
||||||
{
|
else {
|
||||||
Write-Host "Finished converted $convertedVideos out of $count videos. - $notConvertedVideos where not converted because error or already correct codec!!" -ForegroundColor Green
|
Write-Host "Finished converted $convertedVideos out of $count videos. - $notConvertedVideos where not converted because error or already correct codec!!" -ForegroundColor Green
|
||||||
Write-Host "$failedVideos have failed!" -ForegroundColor Red
|
Write-Host "$failedVideos have failed!" -ForegroundColor Red
|
||||||
|
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
encoder/avfilter-8.dll
Normal file
BIN
encoder/avfilter-8.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
encoder/avformat-59.dll
Normal file
BIN
encoder/avformat-59.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
encoder/avutil-57.dll
Normal file
BIN
encoder/avutil-57.dll
Normal file
Binary file not shown.
Binary file not shown.
BIN
encoder/libvmaf.dll
Normal file
BIN
encoder/libvmaf.dll
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
encoder/swresample-4.dll
Normal file
BIN
encoder/swresample-4.dll
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user