Skip to content

Instantly share code, notes, and snippets.

@patelneel55
Last active August 5, 2023 13:29
Show Gist options
  • Save patelneel55/c040e97de474134486f0e9614c13b8c9 to your computer and use it in GitHub Desktop.
Save patelneel55/c040e97de474134486f0e9614c13b8c9 to your computer and use it in GitHub Desktop.
video-merge.ps1 - Merge multiple media files into a single or a group of files using ffmpeg
#########################################
# Quick script to merge video files #
#########################################
<#
.SYNOPSIS
Concatenates a list of video files into one or multiple video files.
.DESCRIPTION
This application allows you to feed it a list of all video files to be combined and combines them to another media files with every file containing 'max' original files.
SUPPORTED INPUT FILE FORMATS: .mkv, .vob, .mp4, .ts
.PARAMETER files
List of comma separated files that need to be combined. Default action is to get all media files in the current folder.
.PARAMETER output_name
Prefix of the final output files. Defaults to "output"
.PARAMETER max
This integer represents the limit of how many of the original files can be combined to a output file. Default value is 0.
.PARAMETER help
Provides usage and command to display this help text.
.PARAMETER default
Run the script using the default provided values.
.PARAMETER quiet
Suppress ffmpeg output
.EXAMPLE
./vide-merge.ps1 -mnum 3
This command will take in all the video files in the current directory and combine them in 3s to provide the output files. For instance, 7 input files will generate 3 output files combining every 3 clips into one clip
.EXAMPLE
./video-merge.ps1 -files ./test.mkv,./hello.mkv,./test2.mkv
This command will combine all the input files into a single output file, "output-1.mkv", since mnum is 0 meaning there is no limit to how many clips a single output file can have.
.EXAMPLE
./video-merge.ps1 -files ./test.mkv,./hello.mp4,./tt.vob,./test2.mkv -mnum 2 -output_name test_output
This command will generate two files with the names, "test_output-1.mkv", "test_output-2.mkv".
#>
# Check for commandline arguments
param(
[switch]$help,
[switch]$default,
[string[]]$files = $(Get-ChildItem -Name *.mkv, *.vob, *.mp4, *.ts),
[string]$output_name = "output",
[int]$max = 0,
[switch]$quiet
)
# Check if help text needs to be printed or no unique input flag was passed.
if($help -or $PSBoundParameters.Count -eq 0)
{
echo "Audio and Video Merger using ffmpeg"
echo "Usage: video-merge.ps1 [-help] [-default] [-files <list>] [-output_name <name>] [-max <value>]"
echo "`t To run using the default settings, run 'video-merge.ps1 -default'"
echo "`n"
Write-Host "Use -h to get full help or, even better, run 'man video-merge.ps1' or 'get-help video-merge.ps1 -detailed'." -ForegroundColor Yellow
exit
}
echo "video-merger.ps1 version 1.0.0."
echo "Audio and Video Merger using ffmpeg"
echo "`n"
# Generate media mpeg transport stream to convert all compressions to the same compression format
$inc = 0
$cmd = ""
$fileArray = @()
ForEach($item in $files)
{
$inc++
$cmd += "ffmpeg -i `"$item`" -f mpegts -c copy file-$inc.mpeg.ts;"
$fileArray += "file-$inc.mpeg.ts"
}
# Check if input files need to be grouped based on max number of files per output file
$inc = 0
if($max -ge 1)
{
# Group files based on max value provided per output file
$files = @()
for($i = 0;$i -lt $fileArray.Length;$i++)
{
$files += $fileArray[$i]
if(($i+1) % $mnum -eq 0)
{
$cmd += "ffmpeg -i `"concat:$($files -join '|')`" -f matroska -c copy '$output_name-$(++$i).mkv';"
$files = @()
}
}
if($files.Length -ne 0)
{
$cmd += "ffmpeg -i `"concat:$($files -join '|')`" -f matroska -c copy '$output_name-$(++$i).mkv';"
}
}
else
{
$cmd += "ffmpeg -i `"concat:$($fileArray -join '|')`" -f matroska -c copy '$output_name.mkv';"
}
# Run all the commands
Invoke-Expression $cmd
# Cleanup temp streams
if($LastExitCode -eq 0)
{
Remove-Item $fileArray
}
echo "`n"
Write-Host "Process Completed." -ForegroundColor Green
@JaragonCR
Copy link

made a change that uses PowerShell 7 Parallel feature, it makes the conversion that much faster,

$cmd = ""
$fileArray = @()
$files | ForEach-object -parallel{
#$inc++
$cmd = "C:\PROGRA~1\ffmpeg\bin\ffmpeg -i $_ -f mpegts -c copy file-$_"
Invoke-Expression $cmd
#$fileArray = $files
} -throttlelimit 100
$fileArray = $(Get-ChildItem -Name file-*)
$cmd = ""

Also consider adding a flag for HW acceleration on ffmpeg & a convert to h265 mp4 flag, reduced my files from 20Gb to 1Gb

C:\PROGRA~1\ffmpeg\bin\ffmpeg -threads 16 -hwaccel cuda -i -preset fast -c:v libx265

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment