Compare commits

..

No commits in common. "windows-hevc-converter" and "master" have entirely different histories.

24 changed files with 254 additions and 1469 deletions

3
Gemfile Normal file
View File

@ -0,0 +1,3 @@
source 'https://rubygems.org'
gem 'streamio-ffmpeg'
gem 'peach'

View File

@ -1,41 +1,56 @@
# Automated HEVC-Video-Converter
# Convert videos in-place to h265 (HEVC)
A PowerShell script for converting video to the HEVC video format using GPU hardware acceleration with NVEnc for Windows.
This is a simple ruby script that will chuch through a directory converting all of the videos to use h.265 or HEVC in place. This works by converting the video file to \*.tmp.mp4, and then moving it to its original file name with the mp4 extension. It will delete the old version of the file.
The main advantage is that you can (usually) save a lot of disk space this way.
![image](/attachments/985e0fa6-ec4a-4ad0-a1c7-d70f59e7a23d)
## Usage
## Space Saving Examples
This is a long running ruby script, it makes calls to FFMPEG using a ruby gem to scrape metadata of videos, and transcode them. It works by appling some simple filters to create a list of videos that can be converted, and then works through that queue.
- 2.5GB MP4 to 500MB HEVC MP4
- 3GB MP4 to 800MB HEVC MP4
Change to the directory, where the config and script is located then run: `$ ruby convertVideos.rb start`
_Results vary and depend on the input video's format, bitrate etc._
## Minimum System Requirements
## Example Config
Please note the preceding colons are important. Also the file must be called config.yml
- Computer with at least two CPU cores and 4GB Ram
- Recent nvidia graphics card ([see: NVENC support matrix](https://developer.nvidia.com/video-encode-decode-gpu-support-matrix))
- Latest nvidia graphics drivers
```
:directory: /mnt/movies
:min_age_days: 5
:log_location: /home/user/logs/hevc_conversion.log
:preset: slow
:threads: 8
:max_new_file_size_ratio: 0.9
```
## Encoding
| Configuration | Description |
| -------- | -------- |
| directory | The directory to recurse into. All files will be considered within that directory. |
|min_age_days | How many days old does this file have to be to be considered for conversion. |
|log_location| This Script is designed to run deetached in the background. As such the log location is the best way to figure out whatis going on and the status of the conversion |
| preset | used to trade off between final file size, quality, and transcoding time. I recomend slow. See ffmpeg docs for more detail. |
|threads | How many threads should be used for converting the file. |
|max_new_file_size_ratio| Once transocing an individual file is finished, this script will make sure the output is smaller than the origional. Spesifically new file size <= Old file size * this value. Since transcoding always involves quality loss this value should be less than 1.0 |
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)
The script converts the files next to the original with '-HEVC' at the end or by replacing the string x264 (old) in the file name with x265.
After conversion, a test of the new video file is performed to ensure its integrity.
If this test is successful, the old file is deleted.
If not, the failed conversion file is deleted and logged.
## Coridnation
When this script starts to convert a video, it creates a .filename.tmp.mp4 file that used the old files filename. This acts as kind of a lock because the exitsance of that file is checked before conversion. This also allows us to save state between runs without needing to share a database or other coridination servcie. That file is left behind if, for any reason, the conversion fails, the process is stopped, or if afterthe conversion the new HEVC file is not at least 10% smaller than the origional. The content is replace with an explination if possible.
## Script Usage
It also makes it so multiple computers can run this script, provided they are all run against the same backing file system (SMB, NFS, etc.). There is a risk of duplicate work if two processes try to start to transcode the same file at the same time, but this risk is minimal for large libraries. To further mitigate, the list of candidate files is randomaized.
1. Clone this repository on your computer
2. Download the latest NVEnc for Windows: https://github.com/rigaya/NVEnc/releases
3. Extract the files to "video-in-place-hevc-converter\encoder\" and replace the old files.
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.
## Extra Content (\_extras folder)
## Setup
- **manually_review_videos.ps1** - Redoes the review process using the "review_needed.log" -> before useing set the "$logFolderName" variable in file.
1. Instal Ruby 2.1.0+
2. Install (ffmpeg)[https://ffmpeg.org/download.html] near version 3.4.4 `# apt-get install ffmpeg`
3. `$ gem install bundler`
4. `$ bundle install`
5. Optional: Install screen or tmux. This is to allows it to run in the background after closing SSH on a server.
6. Edit the script if you want.
7. Run the script.
8. Automate it e.g. with cron?
## Disclaimers
- Only use with videos you have the rights to copy
- This will delete the original video, so use with care. Test with a test directory before running on your entire library.
- Use a test file with all your media playing devices to ensure that they can handle HEVC encoding.

View File

@ -1,304 +0,0 @@
# Converts videos back to x264 for given path: (Video resolution is same as source up to 8K)
# Converter: https://github.com/rigaya/NVEnc/releases
# Forces a higher resolution with ffmpeg than actually intended for the x264 standard.
# Workaround to createn non-standart 8K x254 videos.
#-----------------------------------------------------------------------
# Edit the $videoPath variable to point to your video-files folder:
$videoPath = 'Z:\__VR_SP_CONTENT\_data'
#-----------------------------------------------------------------------
$forceReviewAll = $false # If set to $true all failed conversions are reviewed even those that are obviously corrupt.
$ffmpegBin = "$PSScriptRoot\ffmpeg\ffmpeg.exe"
$fileTester = "$PSScriptRoot\..\mediainfo.exe"
$reviewPlayer = "C:\Program Files\VideoLAN\VLC\vlc.exe"
#############################################################################################################
# Testing and conversion preparations #
#############################################################################################################
if(!(Test-Path $ffmpegBin -PathType leaf))
{
Write-Host "ffmpeg.exe not found, please check path in `"$ffmpegBin`"." -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 -eq "HEVC")
{
# Configure new file naming:
if ($video -match "265")
{
$outputFile = $videoPath + "\" + $video.Replace("265", "264")
} else {
$outputFile = $videoPath + "\" + $video.Insert(($video.Length - 4), '-x264')
}
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 AVC --audio-copy 1,2,3,4 --sub-copy 1,2,3,4 --profile $profile --output `"$outputFile`""
$arguments = "-i `"$inputFile`" -c:v libx264 -preset fast -crf 18 -c:a copy -map 0 -map_metadata 0 -movflags +faststart -pix_fmt yuv420p `"$outputFile`""
Start-Process $ffmpegBin -ArgumentList $arguments -WindowStyle Minimized
#$processName = 'NVEncC64'
$processName = 'ffmpeg'
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

View File

@ -1,326 +0,0 @@
# Converts videos back to x264 for VR playback for given path:
# Converter: https://github.com/rigaya/NVEnc/releases
# Maximum VR Video Dimensions for Oculus Go are: 3840x2048 pixel!! Higher resolution ends with blackscreen!
# Maximum resolution for x264 codec is = 4096x4096 pixel!
#-----------------------------------------------------------------------
# Edit the $videoPath variable to point to your video-files folder:
$videoPath = 'Z:\__VR_SP_CONTENT\_data'
#-----------------------------------------------------------------------
$debug = $true
$forceReviewAll = $false # If set to $true all failed conversions are reviewed even those that are obviously corrupt.
$forceReconvertAllToMatchVRresolution = $true; # only x264 videos AND videos not bigger than 3840x2048 pixel are playable on the Oculus Go.
$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
# Get and check File info for codec and resolution, 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
$reconvert = $false
$resolution_width = $fileDetails.media.track[1].Width
$resolution_height = $fileDetails.media.track[1].Height
if($resolution_width -gt '3840') # max resolution for x264 = 4096
{
if ($forceReconvertAllToMatchVRresolution)
{
$reconvert = $true
}
$new_resolution_width = '3840'
$new_resolution_height = $resolution_height / $resolution_width * $new_resolution_width
if ($new_resolution_height -gt '2048')
{
$new_resolution_width = $new_resolution_width / $new_resolution_height * '2048'
$new_resolution_height = '2048'
}
}
# If not already x264 or reconvert, converting video using NVEncC64:
if(($codec -eq "HEVC") -or ($reconvert))
{
# Configure new file naming:
if ($video -match "265")
{
$outputFile = $videoPath + "\" + $video.Replace("265", "264")
} else {
$outputFile = $videoPath + "\" + $video.Insert(($video.Length - 4), '-x264')
}
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 AVC --audio-copy 1,2,3,4 --sub-copy 1,2,3,4 --profile high --output-res $($new_resolution_width)x$($new_resolution_height) --output `"$outputFile`""
if ($debug)
{
Write-Host "Starting conversion of next file with the following command:"
Write-Host "$NVEncoder $arguments" -ForegroundColor Green
}
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

View File

@ -1,332 +0,0 @@
# Converts videos back to x264 for VR playback for given path:
# Converter: https://github.com/FFmpeg/FFmpeg
# Maximum VR Video Dimensions for Oculus Go are: 3840x2048 pixel!! Higher resolution ends with blackscreen!
# Maximum resolution for x264 codec is = 4096x4096 pixel!
#-----------------------------------------------------------------------
# Edit the $videoPath variable to point to your video-files folder:
$videoPath = 'Z:\__VR_SP_CONTENT\__TODO'
#-----------------------------------------------------------------------
$debug = $true
$forceReviewAll = $false # If set to $true all failed conversions are reviewed even those that are obviously corrupt.
$forceReconvertAllToMatchVRresolution = $true; # only x264 videos AND videos not bigger than 3840x2048 pixel are playable on the Oculus Go.
$ffmpegBin = "$PSScriptRoot\ffmpeg\ffmpeg.exe"
$fileTester = "$PSScriptRoot\..\mediainfo.exe"
$reviewPlayer = "C:\Program Files\VideoLAN\VLC\vlc.exe"
#############################################################################################################
# Testing and conversion preparations #
#############################################################################################################
if(!(Test-Path $ffmpegBin -PathType leaf))
{
Write-Host "ffmpeg.exe not found, please check path in `"$ffmpegBin`"." -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
# Get and check File info for codec and resolution, 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
$reconvert = $false
$resolution_width = $fileDetails.media.track[1].Width
$resolution_height = $fileDetails.media.track[1].Height
if($resolution_width -gt '3840') # max resolution for x264 = 4096
{
if ($forceReconvertAllToMatchVRresolution)
{
$reconvert = $true
}
$new_resolution_width = '3840'
$new_resolution_height = $resolution_height / $resolution_width * $new_resolution_width
if ($new_resolution_height -gt '2048')
{
$new_resolution_width = $new_resolution_width / $new_resolution_height * '2048'
$new_resolution_height = '2048'
}
}
# If not already x264 or reconvert, converting video using ffmpeg:
if(($codec -eq "HEVC") -or ($reconvert))
{
# Configure new file naming:
if ($video -match "265")
{
$outputFile = $videoPath + "\" + $video.Replace("265", "264")
} else {
$outputFile = $videoPath + "\" + $video.Insert(($video.Length - 4), '-x264')
}
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
$rescale = ""
if ($reconvert)
{
$rescale = "-s $($new_resolution_width)x$($new_resolution_height)"
}
# If the Subtitles should not be copied, delete the "--sub-copy 1,2" argument.
$arguments = "-i `"$inputFile`" -c:v libx264 -preset fast -crf 18 -c:a copy -map 0 -map_metadata 0 -movflags +faststart -pix_fmt yuv420p $rescale `"$outputFile`""
if ($debug)
{
Write-Host "Starting conversion of next file with the following command:"
Write-Host "$ffmpegBin $arguments" -ForegroundColor Green
}
Start-Process $ffmpegBin -ArgumentList $arguments -WindowStyle Minimized
$processName = 'ffmpeg'
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
[Int]$processorAffinity = [math]::Pow(2,$($noOfCores).Sum) - 1
#
$process = Get-Process $processName; $process.ProcessorAffinity=$processorAffinity
#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

View File

@ -1,115 +0,0 @@
# 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 = 'Z:\__VR_SP_CONTENT\_data'
#-----------------------------------------------------------------------
$fileTester = "$PSScriptRoot\..\mediainfo.exe"
#############################################################################################################
# Testing and conversion preparations #
#############################################################################################################
# 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
# 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") + ' - [preList - convert HEVC to x264 created 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\ -Name $logFolderName > $null
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 generation of list.." -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 -eq "HEVC")
{
# Configure new file naming:
if ($video -match "265")
{
$outputFile = $videoPath + "\" + $video.Replace("265", "264")
} else {
$outputFile = $videoPath + "\" + $video.Insert(($video.Length - 4), '-x264')
}
Write-Host "Analyzing video ($videoID of $count), needs conversion - number: $($convertedVideos + 1)" -ForegroundColor Magenta
Write-Host "$video `nto:`n$outputFile" -ForegroundColor White
Write-Host
Write-Host
Write-Host "------------------------------------------------------------------------------------------------"
$convertedVideos = $convertedVideos + 1
$Logfile = "$PSScriptRoot\$logFolderName\needs_conversion.log"
LogWrite "$outputFile"
} 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\$logFolderName\already_correct_codec.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.
}
#############################################################################################################
Read-Host -Prompt "Press Enter to exit"
#############################################################################################################
# END - conversion script

View File

@ -1,4 +0,0 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

View File

@ -1,68 +0,0 @@
# Review converted videos:
#-----------------------------------------------------------------------
# Edit the $logFolderName variable to point to your desired logs folder:
#$logFolderName = "24-06-2020 - [run started at 17-31]"
$logFolderName = "2020-10-03 - [run started at 11-29]"
#-----------------------------------------------------------------------
$reviewPlayer = "C:\Program Files\VideoLAN\VLC\vlc.exe"
#############################################################################################################
# Evaluation part of the conversion script #
#############################################################################################################
if(!(Test-Path $reviewPlayer -PathType leaf))
{
Write-Host "vlc.exe not found, is the player installed? please check path in `"$reviewPlayer`"." -ForegroundColor Yellow
Read-Host -Prompt "Press Enter to exit"
exit
}
$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
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
}
Read-Host -Prompt "Press Enter to exit"
#############################################################################################################
# END - conversion script

6
config.yml Normal file
View File

@ -0,0 +1,6 @@
:min_age_days: 0
:directory: /mnt/movies
:log_location: ./log.txt
:preset: slower
:threads: 8
:max_new_file_size_ratio: 0.9

204
convertVideos.rb Normal file
View File

@ -0,0 +1,204 @@
require 'rubygems'
require 'streamio-ffmpeg'
require 'fileutils'
require 'logger'
require 'yaml'
require 'peach'
VID_FORMATS = %w[.avi .flv .mkv .mov .mp4]
# Loads config file:
@config=YAML.load(File.read("./config.yml"))
# Logger setup stuff:
@logger=Logger.new(@config[:log_location])
@logger.level=Logger::INFO
@logger.info "\n New Run starting now......"
@logger.info "Config is being used: #{@config}"
# Check the file age:
def file_age(name)
(Time.now - File.ctime(name))/(24*3600)
end
def seconds_to_s(total_time)
total_time=total_time.to_int
return [total_time / 3600, total_time/ 60 % 60, total_time % 60].map { |t| t.to_s.rjust(2,'0') }.join(':')
end
# Creates a list (array) of all aged files:
def get_aged_files(directory)
out=[]
Dir.foreach(directory){|file|
next if file == '.' or file == '..' or file.start_with?('.')
fileName=File.join(directory,file)
if(File.file?(fileName)) then
if VID_FORMATS.include? File.extname(file) then
if(file_age(fileName)>=@config[:min_age_days]) then
out<<fileName
end
end
elsif File.directory?(fileName) then
out+=get_aged_files(fileName)
end
}
return out
end
# Returns a hash:
def get_candidate_files(possibileFiles)
out={
movies: [],
runtime: 0
}
times=[]
possibileFiles.peach(4) do |file|
if does_video_need_conversion?(file)
out[:movies]<<file
movie=FFMPEG::Movie.new(file)
times<<movie.duration
end
end
times.each{|time|
out[:runtime]=out[:runtime]+=time
}
out[:movies].shuffle!
return out
end
# Check if video needs conversion or not:
def does_video_need_conversion?(file)
movie=FFMPEG::Movie.new(file)
if movie.valid? then
if movie.video_codec!="hevc" then
unless File.exist?(get_temp_filename(file))
return true
end
end
end
return false
end
def get_base_name(file)
outFileName=File.join(
File.dirname(file),
"#{File.basename(file,'.*')}")
end
def get_temp_filename(file)
"#{File.join(
File.dirname(file),
".#{File.basename(file,'.*')}")}.tmp.mp4"
end
def safe_convert_file(original_video,filename)
begin
return convert_file(original_video,filename)
rescue StandardError => e
@logger.error "Problem processing a video"
@logger.error e
end
return nil
end
# Main function for conversion:
def convert_file(original_video,filename)
options={
video_codec: 'libx265',
threads: @config[:threads],
custom: "-preset #{@config[:preset]} -crf 25 -c:a copy".split
}
outFileName = get_base_name(filename)
error_thrown=nil
begin
startTime=Time.now
out = original_video.transcode(get_temp_filename(filename),options){ |progress|
duration=Time.now-startTime
remaining=(duration/progress)*(1-progress)
if(remaining>99999999) then
print "Progress converting #{filename.split('/').last} : #{(progress*100).round(1)}% \r"
else
print "Progress converting #{filename.split('/').last} : #{(progress*100).round(1)}% ETA is #{seconds_to_s(remaining)} \r"
end
}
rescue StandardError => e
error_thrown=e
puts e.to_s
end
puts "Done with #{filename.split('\\').last}"
if ( error_thrown )
@logger.error "A video file failed to transcode correctly"
@logger.error error_thrown
FileUtils.rm(get_temp_filename(filename)) if File.exists?(get_temp_filename(filename))
FileUtils.touch(get_temp_filename(filename))
File.write(get_temp_filename(filename),
[
'An exception occured while transocding this movie.',
error_thrown
].join('\n'))
elsif (out.size>original_video.size*@config[:max_new_file_size_ratio])
@logger.warn "A video file, after transcoding was not at least #{@config[:max_new_file_size_ratio]} the size of the origional (new: #{out.size} old: #{original_video.size}). Keeping origonal #{filename}"
FileUtils.rm(get_temp_filename(filename))
FileUtils.touch(get_temp_filename(filename))
File.write(get_temp_filename(filename), "transcoded video not enough smaller than the origional.")
return nil
else
FileUtils.mv(get_temp_filename(filename),"#{outFileName}.mp4")
if filename!="#{outFileName}.mp4" then
FileUtils.rm(filename)
end
return out
end
end
def status(app)
possible_files=get_aged_files(@config[:directory])
puts "There are a total of #{possible_files.size} files that may need to be converted."
candidate_files= get_candidate_files(possible_files)
puts "There are a total of #{candidate_files[:movies].size} files that have not been converted yet."
puts "Total Duration: #{seconds_to_s(candidate_files[:runtime])}"
end
@total_processing_time=0
@processed_video_duration=0
def iterate
possible_files=get_aged_files(@config[:directory])
@logger.info "There are a total of #{possible_files.size} files that may need to be converted."
@logger.debug "Files to be checked: #{possible_files}"
candidate_files= get_candidate_files(possible_files)
@logger.info "There are a total of #{candidate_files[:movies].size} files that have not been converted yet."
@logger.debug "Candidate Files that need to be re-encoded: #{candidate_files}"
@logger.info "Total Duration: #{seconds_to_s(candidate_files[:runtime])}"
remaining_runtime=candidate_files[:runtime]
candidate_files[:movies].each_with_index do |file,index|
@logger.info "Starting to transcode file #{index+1} of #{candidate_files[:movies].size}: #{file}"
unless does_video_need_conversion?(file)
@logger.info "Video already converted, scanning again"
return true
end
startTime=Time.now
video=FFMPEG::Movie.new(file)
converted_video=safe_convert_file(video,file)
duration=Time.now - startTime
remaining_runtime-=video.duration
if !converted_video.nil? then
@total_processing_time+=duration
@processed_video_duration+=video.duration
end
avg=@processed_video_duration/@total_processing_time
@logger.info "Average videotime/walltime: #{avg} Estimated time remaining #{seconds_to_s(remaining_runtime/avg)}"
end
return false
end
while iterate do end

View File

@ -1,290 +0,0 @@
# 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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

4
logs/.gitignore vendored
View File

@ -1,4 +0,0 @@
# Ignore everything in this directory
*
# Except this file
!.gitignore

Binary file not shown.