Last active
April 23, 2024 09:24
-
-
Save sampalmer/9a0ccaafde3c3edc88dcdf84879f388d to your computer and use it in GitHub Desktop.
PowerShell script to split video into multiple files using ffmpeg
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
param ( | |
[Parameter(Mandatory=$true)] | |
[string]$inVideoPath, | |
[Parameter(Mandatory=$false)] | |
[string]$outVideoDirectory | |
) | |
$ErrorActionPreference = "Stop" | |
$ffmpegCommand = 'ffmpeg' | |
# Validation | |
if (!(Test-Path $inVideoPath)) { | |
throw 'Input file does not exist: ' + $inVideoPath | |
} | |
if (!(Test-Path $inVideoPath -PathType Leaf)) { | |
throw 'Input path is not a file: ' + $inVideoPath | |
} | |
$fileExtension = [io.path]::GetExtension($inVideoPath) | |
if (!$fileExtension) { | |
throw 'Input file has no extension: ' + $inVideoPath | |
} | |
if ($outVideoDirectory) { | |
if (!(Test-Path $outVideoDirectory)) { | |
throw 'Output path does not exist: ' + $outVideoDirectory | |
} | |
if (!(Test-Path $outVideoDirectory -PathType Container)) { | |
throw 'Output path is not a directory: ' + $outVideoDirectory | |
} | |
} | |
# Input | |
Write-Host 'Enter split points in the format "m:ss[ filename]". Use a blank line to finish.' | |
$inlines = @() | |
while ($true) { | |
$inline = Read-Host | |
if ($inline -eq '') { | |
break | |
} | |
$inlines += $inline | |
} | |
$splitPoints = @() | |
foreach ($inline in $inlines) { | |
$regex = '^\s*(\d+:[0-5][0-9]+(.[0-9]+)?)(\s+([^' + [Regex]::Escape(-join [System.Io.Path]::GetInvalidFileNameChars()) + ']+))?\s*$' | |
$valid = $inline -match $regex | |
if (!$valid) { | |
throw 'Invalid format: ' + $inline | |
} | |
$splitPoint = @{ | |
Offset = $Matches[1] | |
FileName = $Matches[3] | |
} | |
if (!$splitPoint.FileName) { | |
$escapedOffset = [Regex]::Replace($splitPoint.Offset, '[.' + [Regex]::Escape(-join [System.Io.Path]::GetInvalidFileNameChars()) + ']', '_') | |
$splitPoint.FileName = [io.path]::GetFileNameWithoutExtension($inVideoPath) + " " + $escapedOffset | |
} | |
# TODO: Detect duplicate file names in the list | |
$splitPoints += $splitPoint | |
} | |
# Preparation | |
$commands = @() | |
for ($i = 0; $i -lt $splitPoints.Length; ++$i) { | |
$splitPoint = $splitPoints[$i] | |
$outVideoFileName = if ([io.path]::HasExtension($splitPoint.FileName)) { $splitPoint.FileName } else { [io.path]::ChangeExtension($splitPoint.FileName, $fileExtension) } | |
$outVideoPath = if ($outVideoDirectory) { Join-Path -Path $outVideoDirectory -ChildPath $outVideoFileName } else { $outVideoFileName } | |
# TODO: Maybe move this check closer to when we will actually create the file | |
if (Test-Path $outVideoPath -PathType Leaf) { | |
throw 'Destination file already exists: ' + $outVideoPath | |
} | |
$toParameter = if ($i -lt $splitPoints.Length - 1) { "-to $($splitPoints[$i + 1].Offset) " } else { '' } | |
$command = @{ | |
Program = $ffmpegCommand | |
Arguments = "-loglevel warning -i ""$inVideoPath"" -c copy -ss $($splitPoint.Offset) $($toParameter)""$outVideoPath""" | |
} | |
$commands += $command | |
} | |
if (!(Get-Command $ffmpegCommand -ErrorAction SilentlyContinue)) { | |
throw "$ffmpegCommand not found in PATH" | |
} | |
# Execution | |
foreach ($command in $commands) { | |
# TODO: On error, clean up | |
$process = New-Object System.Diagnostics.Process | |
$process.StartInfo.FileName = $command.Program | |
$process.StartInfo.Arguments = $command.Arguments | |
$process.StartInfo.UseShellExecute = $false | |
$process.StartInfo.RedirectStandardError = $true | |
$process.StartInfo.WorkingDirectory = Get-Location | |
Write-Host ($process.StartInfo.FileName + ' ' + $process.StartInfo.Arguments) | |
$process.Start() > $null | |
$output = $process.StandardError.ReadToEnd() | |
$process.WaitForExit() | |
if ($output.Trim()) { | |
Write-Host $output | |
} | |
if ($process.ExitCode -ne 0) { | |
throw "$($process.StartInfo.FileName) exited with code $($process.ExitCode)" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment