You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
video-in-place-hevc-converter/convert_Videos.ps1

290 lines
13 KiB
PowerShell

# Converts videos to HEVC for given path:
# https://github.com/rigaya/NVEnc/releases
#-----------------------------------------------------------------------
# Edit the $videoPath variable to point to your video-files folder:
#$videoPath = 'M:\1_movies\_main.movies'
$videoPath = 'M:\2_serien\_main.series'
#$videoPath = 'M:\3_dokus'
#-----------------------------------------------------------------------
# HEVC profiles: main, main10, main444
$hevc_profile = 'main10'
$forceReviewAll = $false # If set to $true all failed conversions are reviewed even those that are obviously corrupt.
$NVEncoder = "$PSScriptRoot\encoder\NVEncC64.exe"
$fileTester = "$PSScriptRoot\mediainfo.exe"
$reviewPlayer = "C:\Program Files\VideoLAN\VLC\vlc.exe"
#############################################################################################################
# Testing and conversion preparations #
#############################################################################################################
if (!(Test-Path $NVEncoder -PathType leaf)) {
Write-Host "NVEncC64.exe not found, please check path in `"$NVEncoder`"." -ForegroundColor Yellow
Read-Host -Prompt "Press Enter to exit"
exit
}
# Get video list from provided path:
$videos = Get-ChildItem -LiteralPath $videoPath -Name -Recurse -Include ('*.mp4', '*.mkv') #('*.avi', '*.mp4', '*.mkv') - avi currently doesn't work.
# Instantiating used variables:
$videoID = 1
$convertedVideos = 0
$notConvertedVideos = 0
$failedVideos = 0
# Square brackets are used as wildcards in Powershell.
# To recognize this as normal text, the LogWite function uses the -LiteralPath parameter instead of the -Path parameter.
$logFolderName = $((Get-Date).tostring("yyyy-MM-dd") + ' - [run started at ' + (Get-Date).tostring("HH-mm") + ']')
$count = $videos.Count
if ($videos.Count -lt 1) {
Write-Host "No videos found in: $videoPath" -ForegroundColor Red
Read-Host -Prompt "Press Enter to exit"
exit
}
# Log write function:
Function LogWrite {
Param ([string]$logstring)
Add-content -LiteralPath $Logfile -value $logstring
}
# Create new log directory:
New-Item -itemType Directory -Path $PSScriptRoot\logs\ -Name $logFolderName > $null
# Calculates the total size of the given directory in GB:
Write-Host "Inizialization in progress.."
$folderSizeInGB = "{0:N2} GB" -f ((Get-ChildItem $videoPath -Recurse | Measure-Object -Property Length -Sum -ErrorAction Stop).Sum / 1GB)
Clear-Host # Clears the upper message from the window
#############################################################################################################
# END - Testing and conversion preparations
#############################################################################################################
# Main conversion process #
#############################################################################################################
Write-Host "Found $count videos with a total size of $folderSizeInGB - starting converter.." -ForegroundColor Cyan
Write-Host
Write-Host
Write-Host "------------------------------------------------------------------------------------------------"
foreach ($video in $videos) {
$video = $video.Replace("`"", "")
$inputFile = $videoPath + "\" + $video
# Pre-file-check if "HEVC" exist in filename skip filechecking:
if ($video -match "HEVC") {
$codec = "HEVC"
}
else {
# 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
$codec = $fileDetails.media.track[1].Format
}
# If not already HEVC, convert video using NVEncC64:
if ($codec -ne "HEVC") {
# Configure new file naming:
if ($video -match "264") {
$outputFile = $videoPath + "\" + $video.Replace("264", "265")
}
else {
$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 "$video `nto:`n$outputFile" -ForegroundColor White
Write-Host
# 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 $hevc_profile --output `"$outputFile`""
Start-Process $NVEncoder -ArgumentList $arguments -WindowStyle Minimized
$processName = 'NVEncC64'
Start-Sleep -Seconds 1
# Sets to use 3 cores (always set to one less core that your CPU has)
# 2 Cores = 3, 3 Cores = 7, 4 cores = 15, 5 cores = 31, 6 cores = 63
# Code to calculate for your CPU:
# $noOfCores = Get-WmiObject Win32_Processor | Measure-Object NumberOfLogicalProcessors -Sum
# $noOfCores.Sum = $noOfCores.Sum - 1
# [math]::Pow(2,$($noOfCores).Sum) - 1
#
$process = Get-Process $processName; $process.ProcessorAffinity = 7
Start-Sleep -Seconds 2
# Sets priorty to High
# Values: High, AboveNormal, Normal, BelowNormal, Low
$process = Get-Process -Id $process.Id
$process.PriorityClass = 'High'
# Waits for process to complete
$processID = (Get-Process $processName).id
Wait-Process -Id $processID
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.
#No characters are interpreted as wildcard characters.
Write-Host "CONVERSION DONE! FILE: `"$outputFile`" FOUND" -ForegroundColor Yellow
Start-Sleep -Seconds 4
# Check if File is valid; the duration of video must be the same! (['media']['track'][0]['Duration']):
$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:
$StreamSize_old, $notused = $($fileDetails.media.track[0].Duration).split('.')
$StreamSize_new, $notused = $($fileDetails_new.media.track[0].Duration).split('.')
Write-Host
Write-Host "Old Duration was: $StreamSize_old `nnew Duration is: $StreamSize_new" -ForegroundColor White
Write-Host
if ($StreamSize_new -eq $StreamSize_old) {
# Delete old video File!
Write-Host "Conversion Successful! - Deleting old file.."
Write-Host
Write-Host "------------------------------------------------------------------------------------------------"
Remove-Item -LiteralPath $inputFile
$convertedVideos = $convertedVideos + 1
$Logfile = "$PSScriptRoot\logs\$logFolderName\successfully_converted.log"
LogWrite "$outputFile"
}
else {
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!
Write-Host "Conversion Done! - Streamsize is not exactly the same. But still OK - Ignoring!"
Write-Host
Write-Host "------------------------------------------------------------------------------------------------"
Remove-Item -LiteralPath $inputFile
$convertedVideos = $convertedVideos + 1
$Logfile = "$PSScriptRoot\logs\$logFolderName\successfully_converted.log"
LogWrite "$outputFile"
}
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!
Write-Host "Conversion Done! - But streamsize is not the same. - Please review!"
Write-Host
Write-Host "------------------------------------------------------------------------------------------------"
$review = $true
$convertedVideos = $convertedVideos + 1
$Logfile = "$PSScriptRoot\logs\$logFolderName\review_needed.log"
LogWrite "$inputFile,$outputFile"
}
else {
if ($forceReviewAll) {
# Mark probably corrupted file for review
Write-Host "Conversion Failed! - Marked for review! because it is desired."
Write-Host
Write-Host "------------------------------------------------------------------------------------------------"
$review = $true
$convertedVideos = $convertedVideos + 1
$Logfile = "$PSScriptRoot\logs\$logFolderName\review_needed.log"
LogWrite "$inputFile,$outputFile"
}
else {
# Delete obviously corrupt File!
Write-Host "Conversion Failded! - Deleting new converted file.." -ForegroundColor Red
Write-Host
Write-Host "------------------------------------------------------------------------------------------------"
Remove-Item -LiteralPath $outputFile
$failedVideos = $failedVideos + 1
$notConvertedVideos = $notConvertedVideos + 1
$Logfile = "$PSScriptRoot\logs\$logFolderName\error_during_conversion.log"
LogWrite "$inputFile,$StreamSize_new,$StreamSize_old,"
}
}
}
}
}
else {
# Alert if video doesn't need conversion:
Write-Host "Analyzing video ($videoID of $count) - skip" -ForegroundColor Magenta
Write-Host "$video is already in correct format!" -ForegroundColor Green
Write-Host
Write-Host "------------------------------------------------------------------------------------------------"
# Increments not converted video counter:
$notConvertedVideos = $notConvertedVideos + 1
$Logfile = "$PSScriptRoot\logs\$logFolderName\skipped_files.log"
LogWrite "$inputFile"
}
# Increments video counter:
$videoID = $videoID + 1
$outputFile = "" # Resets the variable to nothing, that in case of an error the old file is not affected.
}
#############################################################################################################
# END - Main conversion process
#############################################################################################################
# Evaluation part of the conversion script #
#############################################################################################################
if ($review) {
$reviewFiles = Get-content -LiteralPath "$PSScriptRoot\logs\$logFolderName\review_needed.log" | Measure-Object Line
$ReviewCount = $reviewFiles.Lines
Write-Host "There are $ReviewCount files to review.." -ForegroundColor Yellow
Read-Host -Prompt "Press Enter to start reviewing first file"
Write-Host
Write-Host "################################################################################################"
$review_count = 1
foreach ($review_pair in Get-Content -LiteralPath "$PSScriptRoot\logs\$logFolderName\review_needed.log") {
$oldFile, $newFile = $review_pair.split(',')
Write-Host "Playing $review_count converted file: $newFile"
Write-Host
# Starting VLC Player with the file to review
Start-Process $reviewPlayer -ArgumentList `"$newFile`"
Start-Sleep -Seconds 6
# Wait until player is closed.
$processID = (Get-Process "vlc").id
Wait-Process -Id $processID
$msg = 'Do you want to keep the newly converted file and delete the old? (N for deleting NEW-file) [Y/N]'
do {
$response = Read-Host -Prompt $msg
} until (($response -eq 'n') -or ($response -eq 'y'))
if ($response -eq 'y') {
Write-Host "delete old file, keep newly converted.."
$to_delete = $oldFile
}
else {
Write-Host "delete newly converted, keep old file"
$to_delete = $newFile
$failedVideos = $failedVideos + 1
$convertedVideos = $convertedVideos - 1
}
Write-Host "DELETED: $to_delete" -ForegroundColor Red
Remove-Item -LiteralPath $to_delete
Write-Host "------------------------------------------------------------------------------------------------"
Start-Sleep -Seconds 2
}
}
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)
if ($notConvertedVideos -eq 0) {
Write-Host "Finished converted $convertedVideos out of $count videos." -ForegroundColor Green
}
else {
if ($failedVideos -eq 0) {
Write-Host "Finished converted $convertedVideos out of $count videos. - $notConvertedVideos where not converted because of already correct codec!" -ForegroundColor Green
}
else {
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 "Directory size before conversion: $folderSizeInGB"
Write-Host "Directory size after conversion: $folderSizeInGB2"
Read-Host -Prompt "Press Enter to exit"
#############################################################################################################
# END - conversion script