Convert Video to HLS

Converts a video file into an HLS stream for web use, with three preset qualities.

using namespace System.Collections.Generic

param (
    [Parameter(Mandatory = $true)]
    [string] $Path,
    # Assumed to be the filename of Path if not set.

    [string] $Name,

    # Assumed to be a directory "Name" if not set.
    [string] $OutputDirectory
)

$audioBitrate = '192k'
$crf = 20
$hlsTime = 4
$variants = @(
    @{
        name = 'high'
        scale = 'w=1920:h=1080'
        bitrate = '5000k'
        maxRate = '5350k'
        bufferSize = '2100k'
    }
    @{
        name = 'medium'
        scale = 'w=1280:h=720'
        bitrate = '2800k'
        maxRate = '2996k'
        bufferSize = '4200k'
    }
    @{
        name = 'low'
        scale = 'w=760:h=540'
        bitrate = '1400k'
        maxRate = '1498k'
        bufferSize = '7500k'
    }
)

[char[]] $TRIM = @('"', ' ')
$_path = $Path.Trim($TRIM)
$_name = $(if([string]::IsNullOrWhiteSpace($Name)) { (Split-Path -Path $_path -LeafBase).ToLowerInvariant() } else { $Name.Trim($TRIM) })
$_outputDirectory = $(
    if([string]::IsNullOrWhiteSpace($OutputDirectory)) { Join-Path -Path (Split-Path -Path $_path -Parent) -ChildPath $_name }
    else { $OutputDirectory.Trim($TRIM) }
)

$ffmpegArgs = [List[string]] @(
    '-i', $_path.Trim('"')
    '-codec:a', 'aac'
    '-codec:v', 'libx264'
    '-crf', $crf
    '-hide_banner'
    '-hls_playlist_type', 'vod'
    '-hls_time', $hlsTime,
    '-profile:v', 'main'
)

for ($i = 0; $i -lt $variants.Count; $i++) {
    $variant = $variants[$i]
    $ffmpegArgs.AddRange([List[string]] @(
        "-b:v:$i", $variant.bitrate
        "-bufsize:v:$i", $variant.bufferSize
        "-filter:v:$i", "scale=$($variant.scale):force_original_aspect_ratio=decrease"
        '-map', '0:v'
        "-maxrate:v:$i", $variant.maxRate
        '-b:a', $audioBitrate
        '-map', '0:a'
    ))
}

$ffmpegArgs.Add('-var_stream_map "' + $(for ($i = 0; $i -lt $variants.Count; $i++) { "v:$i,a:$i,name:$($variants[$i].name)" }) + '"')

$ffmpegArgs.AddRange([List[string]] @(
    '-master_pl_name', 'master.m3u8'
    (Join-Path -Path $_outputDirectory -ChildPath '%v.m3u8')
))

if (-not (Test-Path -Path $_outputDirectory)) { New-Item -Path $_outputDirectory -ItemType Directory -ErrorAction Stop > $null }
Start-Process -FilePath 'ffmpeg' -ArgumentList $ffmpegArgs -Wait -NoNewWindow -ErrorAction Stop

Run like ConvertToHLS.ps1 -Path MyVideo.mp4.