使用PowerShell和FFMPEG将音频和字幕源条带化并添加到INDEX.M3U8

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用PowerShell和FFMPEG将音频和字幕源条带化并添加到INDEX.M3U8相关的知识,希望对你有一定的参考价值。

我正在使用自定义脚本将视频文件转换为多分辨率HLS。我已切换到新的网络播放器,它将允许我支持字幕轨道和音频轨道选择。

[我很难弄清楚如何编辑脚本以使用.MKV并剥离所有音频源和字幕源并将其添加到INDEX.M3U8

我当前的脚本:

$sw = [Diagnostics.Stopwatch]::StartNew()
$files = Get-ChildItem ${Get-Location}
$loco = Get-Location
$p1 = Join-Path -Path $loco -ChildPath "/out"
echo $p1
New-Item -ItemType Directory -Force -Path $p1
foreach ($f in $files){ 
$p2 = Join-Path -Path $loco -ChildPath "/out/" | Join-Path -ChildPath $f
$sb = [System.Text.StringBuilder]::new();
[void]$sb.AppendLine( '#EXTM3U' )
[void]$sb.AppendLine( '#EXT-X-VERSION:3' )
[void]$sb.AppendLine( '#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360' )
[void]$sb.AppendLine( '360p.m3u8' )
[void]$sb.AppendLine( '#EXT-X-STREAM-INF:BANDWIDTH=1400000,RESOLUTION=842x480' )
[void]$sb.AppendLine( '480.m3u8' )

New-Item -ItemType Directory -Force -Path $p2
$resStr = ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=s=x:p=0 $f.FullName;
$res = [convert]::ToInt32($resStr)
#ffmpeg -i $f.FullName -c:a copy -vf scale=w=640:h=360:force_original_aspect_ratio=decrease -c:a aac -ar 48000  -rc cqp -qp_p 0 -qp_i 1 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 4 -hls_playlist_type vod  -b:v 800k -maxrate 856k -bufsize 1200k -b:a 96k -hls_segment_filename out/$f/360p_%03d.ts out/$f/360p.m3u8 -vf scale=w=842:h=480:force_original_aspect_ratio=decrease -c:a aac -ar 48000 -gpu 1 -c:v h264_amf -rc cqp -qp_p 0 -qp_i 1 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 4 -hls_playlist_type vod -b:v 1400k -maxrate 1498k -bufsize 2100k -b:a 128k -hls_segment_filename out/$f/480p_%03d.ts out/$f/480p.m3u8 -vf  scale=w=1280:h=720:force_original_aspect_ratio=decrease -c:a aac -ar 48000 -gpu 1 -c:v h264_amf -rc cqp -qp_p 0 -qp_i 1 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 4 -hls_playlist_type vod -b:v 2800k -maxrate 2996k -bufsize 4200k -b:a 128k -hls_segment_filename out/$f/720p_%03d.ts out/$f/720p.m3u8 -vf  scale=w=1920:h=1080:force_original_aspect_ratio=decrease -c:a aac -ar 48000 -gpu 1 -c:v h264_amf -rc cqp -qp_p 0 -qp_i 1 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 4 -hls_playlist_type vod -b:v 5000k -maxrate 5350k -bufsize 7500k -b:a 192k -hls_segment_filename out/$f/1080p_%03d.ts out/$f/1080p.m3u8
#ffmpeg -hwaccel auto -hwaccel_device 0 -i $f.FullName -c:v h264 -profile:v main -c:a aac -filter:v scale=360:640 -ar 48000  -rc cqp -qp_p 0 -qp_i 1 -profile:v main -crf 23 -sc_threshold 0 -g 48 -b:v 800k -maxrate 856k -bufsize 1200k -b:a 96k  -keyint_min 4 -start_number 0 -hls_time 10 -hls_playlist_type vod  -hls_list_size 0 -f hls -hls_segment_filename out/$f/360p_%03d.ts out/$f/360p.m3u8 
ffmpeg -hwaccel auto -hwaccel_device 0 -i $f.FullName -c:v h264_nvenc -b:v 200k -minrate 100k -maxrate 896k -profile:v main -c:a aac -filter:v scale=-1:360 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls -hls_segment_filename out/$f/360p_%03d.ts out/$f/360p.m3u8 
ffmpeg -hwaccel auto -hwaccel_device 0 -i $f.FullName -c:v h264_nvenc -b:v 1000k -minrate 896k -maxrate 1536k -profile:v main -c:a aac -filter:v scale=-1:480 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls -hls_segment_filename out/$f/480p_%03d.ts out/$f/480p.m3u8
If($res -ge 720) {
    ffmpeg -hwaccel auto -hwaccel_device 0 -i $f.FullName -c:v h264_nvenc -b:v 2232k -minrate 1856k -maxrate 2872k -profile:v main -c:a aac -filter:v scale=-1:720 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls -hls_segment_filename out/$f/720p_%03d.ts out/$f/720p.m3u8
    [void]$sb.AppendLine( '#EXT-X-STREAM-INF:BANDWIDTH=2800000,RESOLUTION=1280x720' )
    [void]$sb.AppendLine( '720p.m3u8' )
}   
If($res -ge 1080) {
    ffmpeg -hwaccel auto -hwaccel_device 0 -i $f.FullName -c:v h264_nvenc -b:v 4632k -minrate 3712k -maxrate 5552k -profile:v main -c:a aac -filter:v scale=-1:1080 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls -hls_segment_filename out/$f/1080p_%03d.ts out/$f/1080p.m3u8
    [void]$sb.AppendLine( '#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080' )
    [void]$sb.AppendLine( '1080p.m3u8' )
}

$p3 = Join-Path -Path $p2 -ChildPath "/index.m3u8"
#echo $index | Out-File -Encoding UTF8 -LiteralPath $p3
echo $sb.ToString()
[System.IO.File]::WriteAllLines($p3, $sb.ToString().Trim().replace("`r`n", "`n"))
 }
 $sw.Stop()
 echo $sw.Elapsed
答案
$sw = [Diagnostics.Stopwatch]::StartNew()
$files = Get-ChildItem ${Get-Location}
$loco = Get-Location
$p1 = Join-Path -Path $loco -ChildPath "/out"
New-Item -ItemType Directory -Force -Path $p1



function lnCodeTransform {
param( $String )
echo $String
switch ($String)
{
    "jpn" {"jp"}
    "eng" {"en"}
    "esp" {"es"}
    "fra" {"fr"}
    "deu" {"de"}
    default {$String}
}
}


function lnNameTransform {
param( $String )
switch ($String)
{
    "jpn" {"Japanese"}
    "eng" {"English"}
    "esp" {"Spanish"}
    "fra" {"French"}
    "deu" {"German"}
    default {$String}
}
}


foreach ($f in $files){ 
if ($f.Name -eq "out"){
    continue;
}
$p2 = Join-Path -Path $loco -ChildPath "/out/" | Join-Path -ChildPath $f
New-Item -ItemType Directory -Force -Path $p2/audio
New-Item -ItemType Directory -Force -Path $p2/video
New-Item -ItemType Directory -Force -Path $p2/subtitle
$sb = [System.Text.StringBuilder]::new();
[void]$sb.AppendLine( '#EXTM3U' )
[void]$sb.AppendLine( '#EXT-X-VERSION:3' )
#[void]$sb.AppendLine( '#EXT-X-STREAM-INF:BANDWIDTH=800000,RESOLUTION=640x360' )
#[void]$sb.AppendLine( '360p.m3u8' )


New-Item -ItemType Directory -Force -Path $p2
$resStr = ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=s=x:p=0 $f.FullName;
$res = [convert]::ToInt32($resStr)
$audioTracks = ffprobe $f.FullName -show_entries stream=index:stream_tags=language -select_streams a -of compact=p=0:nk=1 
$audioTracks = $audioTracks.split("
")
foreach($audio in $audioTracks) {
    $ID = $audio.split("|")[0];
    $audioName = $audio.split("|")[1];
    ffmpeg -i $f.FullName -threads 0 -muxdelay 0 -y -map 0:$ID -codec aac -f segment -segment_time 10 -segment_list_size 0 -segment_list out/$f/audio/audio_"$ID.m3u8" -segment_format mpegts out/$f/audio/"audio_$ID""_%d.ts"
    $name = lnNameTransform($audioName)
    $code = lnCodeTransform($audioName)
    [void]$sb.AppendLine( "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=`"aac`",LANGUAGE=`"$code`",NAME=`"$name`",DEFAULT=NO,AUTOSELECT=NO,URI=`"audio/audio_$ID.m3u8`"" )
}
$subTracks = ffprobe $f.FullName -show_entries stream=index:stream_tags=language -select_streams s -of compact=p=0:nk=1 
$subTracks = $subTracks.split("")
foreach($subtitle in $subTracks) {
    $ID = $subtitle.split("|")[0];
    $subName = $subtitle.split("|")[1];
    ffmpeg -i $f.FullName -map 0:$ID -f segment -segment_time 10 -segment_list_size 0 -segment_list out/$f/subtitle/sub_"$subName.m3u8" -segment_format webvtt -scodec webvtt out/$f/subtitle/"sub_$subName%d.vtt"
    $name = lnNameTransform($subName)
    $code = lnCodeTransform($subName)
    [void]$sb.AppendLine( "#EXT-X-MEDIA:TYPE=SUBTITLES,GROUP-ID=`"subs`",LANGUAGE=`"$code`",NAME=`"$name`",FORCED=NO,AUTOSELECT=NO,URI=`"subtitle/sub_$subName.m3u8`"" )
}

[void]$sb.AppendLine( '#EXT-X-STREAM-INF:BANDWIDTH=1400000,CODECS="avc1.4d4015,mp4a.40.2",RESOLUTION=842x480,AUDIO="aac",SUBTITLES="subs"' )
[void]$sb.AppendLine( 'video/480p.m3u8' )
#ffmpeg -i $f.FullName -c:a copy -vf scale=w=640:h=360:force_original_aspect_ratio=decrease -c:a aac -ar 48000  -rc cqp -qp_p 0 -qp_i 1 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 4 -hls_playlist_type vod  -b:v 800k -maxrate 856k -bufsize 1200k -b:a 96k -hls_segment_filename out/$f/360p_%03d.ts out/$f/360p.m3u8 -vf scale=w=842:h=480:force_original_aspect_ratio=decrease -c:a aac -ar 48000 -gpu 1 -c:v h264_amf -rc cqp -qp_p 0 -qp_i 1 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 4 -hls_playlist_type vod -b:v 1400k -maxrate 1498k -bufsize 2100k -b:a 128k -hls_segment_filename out/$f/480p_%03d.ts out/$f/480p.m3u8 -vf  scale=w=1280:h=720:force_original_aspect_ratio=decrease -c:a aac -ar 48000 -gpu 1 -c:v h264_amf -rc cqp -qp_p 0 -qp_i 1 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 4 -hls_playlist_type vod -b:v 2800k -maxrate 2996k -bufsize 4200k -b:a 128k -hls_segment_filename out/$f/720p_%03d.ts out/$f/720p.m3u8 -vf  scale=w=1920:h=1080:force_original_aspect_ratio=decrease -c:a aac -ar 48000 -gpu 1 -c:v h264_amf -rc cqp -qp_p 0 -qp_i 1 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 -hls_time 4 -hls_playlist_type vod -b:v 5000k -maxrate 5350k -bufsize 7500k -b:a 192k -hls_segment_filename out/$f/1080p_%03d.ts out/$f/1080p.m3u8
#ffmpeg -hwaccel auto -hwaccel_device 0 -i $f.FullName -c:v h264_nvenc -preset slow -pix_fmt yuv420p -c:a aac -filter:v scale=360:640 -ar 48000  -rc cqp -qp_p 0 -qp_i 1 -profile:v main -crf 23 -sc_threshold 0 -g 48 -b:v 800k -maxrate 856k -bufsize 1200k -b:a 96k  -keyint_min 4 -start_number 0 -hls_time 10 -hls_playlist_type vod  -hls_list_size 0 -f hls -hls_segment_filename out/$f/360p_%03d.ts out/$f/360p.m3u8 
#ffmpeg -hwaccel auto -hwaccel_device 0 -i $f.FullName -c:v h264 -profile:v main -c:a aac -filter:v scale=360:640 -start_number 0 -hls_time 10 -hls_list_size 0 -f hls -hls_segment_filename out/$f/360p_%03d.ts out/$f/360p.m3u8 
ffmpeg -i $f.FullName -c:v h264_nvenc -crf 22 -preset slow -pix_fmt yuv420p -filter:v scale="trunc(oh*a/2)*2:480" -map 0:v -start_number 0 -hls_time 10 -hls_list_size 0 -f hls -hls_segment_filename out/$f/video/480p_%03d.ts out/$f/video/480p.m3u8
If($res -ge 720) {
    ffmpeg -i $f.FullName -c:v h264_nvenc -crf 20 -preset slow -pix_fmt yuv420p -filter:v scale="trunc(oh*a/2)*2:720" -map 0:v -start_number 0 -hls_time 10 -hls_list_size 0 -f hls -hls_segment_filename out/$f/video/720p_%03d.ts out/$f/video/720p.m3u8
    [void]$sb.AppendLine( '#EXT-X-STREAM-INF:BANDWIDTH=2800000,CODECS="avc1.4d4015,mp4a.40.2",RESOLUTION=1280x720,AUDIO="aac",SUBTITLES="subs"' )
    [void]$sb.AppendLine( 'video/720p.m3u8' )
}   
If($res -ge 1080) {
    ffmpeg -i $f.FullName -c:v h264_nvenc -crf 18 -preset slow -pix_fmt yuv420p -filter:v scale="trunc(oh*a/2)*2:1080" -map 0:v -start_number 0 -hls_time 10 -hls_list_size 0 -f hls -hls_segment_filename out/$f/video/1080p_%03d.ts out/$f/video/1080p.m3u8
    [void]$sb.AppendLine( '#EXT-X-STREAM-INF:BANDWIDTH=5000000,CODECS="avc1.4d4015,mp4a.40.2",RESOLUTION=1920x1080,AUDIO="aac",SUBTITLES="subs"' )
    [void]$sb.AppendLine( 'video/1080p.m3u8' )
}

$p3 = Join-Path -Path $p2 -ChildPath "/index.m3u8"
#echo $index | Out-File -Encoding UTF8 -LiteralPath $p3
echo $sb.ToString()
[System.IO.File]::WriteAllLines($p3, $sb.ToString().Trim().replace("`r`n", "`n"))
}
$sw.Stop()
echo $sw.Elapsed

以上是关于使用PowerShell和FFMPEG将音频和字幕源条带化并添加到INDEX.M3U8的主要内容,如果未能解决你的问题,请参考以下文章

FFMPEG 更改音频和字幕的 fps 并合并 2 个文件

FFMPEG 同时编码音频和强制字幕?

android ffmpeg视频添加字幕和配音

FFmpeg基础库编程开发学习笔记——音频常见格式及字幕格式

FFmpeg在JAVA中的使用-音频提取&字幕压缩

FFmpegffplay 播放视频命令 ( 播放 | 暂停 | 停止 | 音量控制 | 进度控制 | 音频流 / 视频流 / 字幕流 / 节目切换 )