FFMPEG HLS 多个轨道不同步

FFMPEG HLS multiple Tracks not in sync

此脚本有效,但视频与副轨或音轨不同步。有人可以帮助解决此问题或帮助我使用新脚本。我一直试图以 0 运气解决这个问题,并让朋友们看过它。我什至去了 FFMPEG discord 和 FB,向过去发布过脚本的其他人寻求帮助。似乎没有人对此感兴趣。请有人帮助我。

我想做的就是将 MKV 批量编码为 HLS,在 10 秒的片段中使用多个分辨率,并包括最初在 MKV 中的所有音频和 SUb 轨道

$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("\n")
    foreach($audio in $audioTracks) {
        $ID = $audio.split("|")[0];
        $audioName = $audio.split("|")[1];
        ffmpeg -i $f.FullName -threads 0 -muxdelay 0 -y -map 0:$ID -async 1 -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 -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 -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 -async 1 -profile:v main -y -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 -profile:v main -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 -profile:v main -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 ``` 
$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 )
    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("\n")
    foreach($audio in $audioTracks) {
        $ID = $audio.split("|")[0];
        $audioName = $audio.split("|")[1];
        ffmpeg -i $f.FullName -ss 0 -y -map 0:$ID -start_number 0 -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 -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 -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 -b:v 1200k -minrate 750k -maxrate 2100k -profile:v main -y -async 1 -force_key_frames:v "expr:gte(t,n_forced*2.000)" -filter:v scale=-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 -b:v 2400k -minrate 1500k -maxrate 4200k -profile:v main -force_key_frames:v "expr:gte(t,n_forced*2.000)" -filter:v scale=-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 900) {
        ffmpeg -i $f.FullName -c:v h264_nvenc -b:v 4800k -minrate 3000k -maxrate 8400k -profile:v main -force_key_frames:v "expr:gte(t,n_forced*2.000)" -filter:v scale=-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 ```