Skip to content

Instantly share code, notes, and snippets.

@sampalmer
Last active April 23, 2024 09:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sampalmer/9a0ccaafde3c3edc88dcdf84879f388d to your computer and use it in GitHub Desktop.
Save sampalmer/9a0ccaafde3c3edc88dcdf84879f388d to your computer and use it in GitHub Desktop.
PowerShell script to split video into multiple files using ffmpeg
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