:HLS切片與ffpreset預(yù)設(shè)實(shí)踐指南)
簡(jiǎn)介一份圍繞FFmpeg視頻轉(zhuǎn)流處理的實(shí)用工具包面向需要進(jìn)行MP4與m3u8格式互轉(zhuǎn)的開(kāi)發(fā)者、運(yùn)維人員及流媒體學(xué)習(xí)者。其中內(nèi)置FFmpeg可執(zhí)行程序、多套libvpx系列ffpreset預(yù)設(shè)文件以及說(shuō)明文檔可直接調(diào)用命令行完成視頻切片與HLS播放列表生成并可通過(guò)conditionmjx等預(yù)設(shè)快速調(diào)整編碼參數(shù)省去手動(dòng)配置的繁瑣。壓縮包共11個(gè)文件涵蓋ffpreset預(yù)設(shè)、css樣式、txt說(shuō)明、exe主程序及xsd定義文件整體約17.46MB結(jié)構(gòu)簡(jiǎn)潔便于攜帶使用。目前已有1514人學(xué)習(xí)下載適合希望掌握HLS流媒體轉(zhuǎn)換、理解m3u8分片原理并落地實(shí)操的用戶(hù)。借助這些文件可快速搭建轉(zhuǎn)換環(huán)境結(jié)合文檔中的命令示例能更清晰地理解hls_time、hls_segment_filename等關(guān)鍵參數(shù)及ffpreset自定義配置方式。1. ffmpeg 在 mp4 與 m3u8 之間的轉(zhuǎn)換為什么值得單獨(dú)整理做視頻相關(guān)開(kāi)發(fā)的人遲早會(huì)撞上這個(gè)組合手里是 mp4播放器要的是 m3u8或者反過(guò)來(lái)拿到一個(gè) m3u8 地址要落盤(pán)成 mp4 做剪輯輸入源。ffmpeg 一條命令就能在兩個(gè)方向之間打通但真跑起來(lái)會(huì)發(fā)現(xiàn)坑不少——切片后 seek 卡頓、合并后音畫(huà)不同步、明明是同一條命令換個(gè)環(huán)境就報(bào) Invalid data。這里面最有迷惑性的是 ffpreset。它常被當(dāng)成 ffmpeg 自帶的參數(shù)記憶工具實(shí)際上它是一套文本預(yù)設(shè)文件批處理里配合條件判斷能讓轉(zhuǎn)碼參數(shù)可控。圍繞這個(gè)標(biāo)題把 m3u8 的切片原理、mp4 的回流合并、預(yù)設(shè)文件的加載機(jī)制和條件化調(diào)用串起來(lái)適合正在寫(xiě)轉(zhuǎn)碼腳本、維護(hù)點(diǎn)播系統(tǒng)或者對(duì)接 HLS 播放源的人。讀完你應(yīng)該能自己搭一條穩(wěn)定的 mp4/m3u8 互轉(zhuǎn)鏈路。2. m3u8 不是視頻格式先看 HLS 索引的組成再看 ffmpeg 怎么切2.1 m3u8 索引文件里的三類(lèi)關(guān)鍵行m3u8 本質(zhì)是 UTF-8 文本最前面必須有#EXTM3U第一行沒(méi)有它就幾乎可以斷定文件損壞。點(diǎn)播型列表常見(jiàn)#EXT-X-PLAYLIST-TYPE:VOD直播型用#EXT-X-TARGETDURATION后接每個(gè)分片的最大秒數(shù)。#EXTINF:6.000000后面跟著 ts 分片文件名這是播放器拉流和 ffmpeg 合并的依據(jù)。本地生成的 m3u8 和線(xiàn)上 CDN 返回的 m3u8 在結(jié)構(gòu)上沒(méi)有本質(zhì)區(qū)別區(qū)別在于分片 URL 是相對(duì)路徑還是絕對(duì)路徑。ffmpeg 的 HLS muxer 默認(rèn)寫(xiě)相對(duì)路徑適合同目錄部署如果分片要傳給遠(yuǎn)端播放器需要加-hls_base_url指定前綴或者在上傳后重寫(xiě)索引。用 ffprobe 看一個(gè) m3u8ffprobe -v error -show_format -show_streams playlist.m3u8輸出里關(guān)注format_name是否為hls以及duration是否和源文件一致。多數(shù)合并失敗都發(fā)生在分片時(shí)長(zhǎng)異常、缺少結(jié)尾#EXT-X-ENDLIST這兩件事上先用這個(gè)命令驗(yàn)證再排查別的。2.2 ffmpeg 切片 mp4 到 m3u8 的最小完整命令ffmpeg -i input.mp4 \ -c:v libx264 -c:a aac \ -hls_time 6 -hls_list_size 0 \ -hls_segment_filename seg_%03d.ts \ -hls_playlist_type vod \ output.m3u8-hls_time 6是每個(gè)分片的目標(biāo)時(shí)長(zhǎng)實(shí)際切片點(diǎn)由關(guān)鍵幀位置決定所以不是嚴(yán)格的 6 秒。-hls_list_size 0讓它把已生成的分片全部寫(xiě)進(jìn)索引直播場(chǎng)景下如果要生成滾動(dòng)列表就把它設(shè)成 5 或 10。-hls_segment_filename控制分片命名%03d是三位序號(hào)如果不寫(xiě)ffmpeg 會(huì)按output0.ts、output1.ts命名文件一多容易混淆。-hls_playlist_type vod表示這是完整點(diǎn)播列表播放器播完不會(huì)繼續(xù)等新分片。這里有個(gè)容易踩的細(xì)節(jié)源文件如果是 H.264 AAC不用重新編碼直接-c copy就能切源文件是 H.265、MPEG-4 或者音頻是 MP3就必須先轉(zhuǎn)碼否則生成的 ts 分片在部分瀏覽器里沒(méi)法播??紤]到兼容性建議統(tǒng)一用-c:v libx264 -c:a aac碼率按源文件給-crf 23即可。2.3 為什么分片時(shí)長(zhǎng)不準(zhǔn)關(guān)鍵幀對(duì)齊和-g的關(guān)系HLS 切片不是按時(shí)間軸硬切而是以「下一個(gè)關(guān)鍵幀」為邊界。ffmpeg 在切片時(shí)如果發(fā)現(xiàn)距離開(kāi)頭已經(jīng)到 6 秒但下一個(gè) IDR 幀在第 7.2 秒它會(huì)把分片延續(xù)到第 7.2 秒。結(jié)果就是#EXTINF里的值經(jīng)常是 6.0、7.2、5.8 混合在一起這是正?,F(xiàn)象。要讓分片更均勻需要在編碼時(shí)就指定關(guān)鍵幀間隔讓關(guān)鍵幀的出現(xiàn)頻率和切片時(shí)長(zhǎng)對(duì)齊ffmpeg -i input.mp4 \ -c:v libx264 -x264-params keyint120:min-keyint120:scenecut0 \ -c:a aac -hls_time 4 \ -hls_segment_filename seg_%03d.ts \ output.m3u8keyint120的含義是每 120 幀放一個(gè)關(guān)鍵幀在 30fps 下正好 4 秒一個(gè)。把scenecut0關(guān)掉場(chǎng)景切換檢測(cè)避免它額外插入關(guān)鍵幀導(dǎo)致分片變短。用這個(gè)組合后-hls_time設(shè)定的值才會(huì)真正貼近實(shí)際分片時(shí)長(zhǎng)。省略這一步做出來(lái)的 m3u8 能播但碼率波動(dòng)大后續(xù)做倍速播放或精確 seek 會(huì)吃虧。3. mp4 轉(zhuǎn) m3u8 的參數(shù)設(shè)計(jì)切片時(shí)長(zhǎng)、編碼器選擇與點(diǎn)播/直播差異3.1 按播放場(chǎng)景選切片時(shí)長(zhǎng)短視頻短切長(zhǎng)視頻長(zhǎng)切切片時(shí)長(zhǎng)的選擇由播放體驗(yàn)決定不是固定用 6 秒。短視頻或互動(dòng)視頻用 2-4 秒切片起播快、拖動(dòng)精準(zhǔn)代價(jià)是分片數(shù)量多HTTP 請(qǐng)求數(shù)成倍上漲長(zhǎng)視頻或公開(kāi)課用 10-15 秒切片請(qǐng)求數(shù)少、CDN 友好代價(jià)是 seek 誤差變大。常見(jiàn)做法是給不同業(yè)務(wù)各留一套預(yù)設(shè)短視頻用-hls_time 3點(diǎn)播電影用-hls_time 8。分片越短碼率波動(dòng)越容易被播放器感知到所以短分片要多給一點(diǎn)編碼碼率余量比如-crf 20替代-crf 23。3.2 編碼器參數(shù)對(duì) m3u8 的實(shí)際影響libx264 與硬件編碼的取舍切片生成 ts 分片時(shí)編碼器輸出的碼流會(huì)被拆成一個(gè)個(gè) GOP幀組。libx264 的 CPU 編碼質(zhì)量穩(wěn)定、參數(shù)細(xì)粒度高適合離線(xiàn)批處理-preset medium是速度和體積的均衡點(diǎn)要更小體積用-preset slower要更快出片用-preset veryfast。注意-preset這一項(xiàng)只影響壓縮耗時(shí)和體積不影響畫(huà)面分辨率和幀率。如果是機(jī)器上插了 NVIDIA 顯卡-c:v h264_nvenc -preset p4 -cq 23可以把轉(zhuǎn)碼速度提升數(shù)倍但同碼率下畫(huà)質(zhì)明顯差于 libx264這個(gè)差距在暗場(chǎng)景和高動(dòng)態(tài)畫(huà)面里尤其明顯。是否用硬件編碼取決于你的場(chǎng)景重速度還是重畫(huà)質(zhì)。轉(zhuǎn)出來(lái)的 ts 分片本身互不依賴(lài)可并行處理但前提是編碼參數(shù)必須完全一致否則播放器在分片切換時(shí)會(huì)出現(xiàn)色彩跳動(dòng)。3.3 直播型 m3u8 與點(diǎn)播型 m3u8 的參數(shù)差異點(diǎn)播列表寫(xiě)死了分片數(shù)量和時(shí)長(zhǎng)生成后不需要再改直播列表需要不斷往 m3u8 里追加新分片同時(shí)把老分片從索引中移除。實(shí)現(xiàn)這種效果ffmpeg -i input.mp4 \ -c:v libx264 -c:a aac \ -hls_time 4 -hls_list_size 10 \ -hls_flags delete_segments \ -hls_playlist_type event \ live.m3u8-hls_list_size 10讓索引只保留最近 10 個(gè)分片-hls_flags delete_segments自動(dòng)刪除已被擠出索引的 ts 文件防止磁盤(pán)被寫(xiě)滿(mǎn)。-hls_playlist_type event是直播和點(diǎn)播的中間態(tài)索引保持追加模式但播放器從頭播。如果要做真正的直播循環(huán)拉流直接把event換成live后會(huì)丟棄老分片播放器會(huì)從最新位置進(jìn)入。3.4 分片加密為 m3u8 增加一層訪(fǎng)問(wèn)控制HLS 支持對(duì)每個(gè)分片做 AES-128 加密這是 m3u8 相對(duì) mp4 分發(fā)路徑的一大優(yōu)勢(shì)。加密流程分兩步先生成 16 字節(jié)的密鑰再指定密鑰文件讓 ffmpeg 在切片時(shí)對(duì)分片加密openssl rand 16 enc.key ffmpeg -i input.mp4 \ -c:v libx264 -c:a aac \ -hls_time 6 -hls_list_size 0 \ -hls_key_info_file key_info.txt \ -hls_playlist_type vod \ enc_output.m3u8key_info.txt的格式是固定的三行密鑰文件的 URI、密鑰文件路徑、IV可選。如果沒(méi)有寫(xiě) IVffmpeg 默認(rèn)使用分片序號(hào)作為 IV。播放器在拉流時(shí)會(huì)先從 m3u8 里讀到#EXT-X-KEY再請(qǐng)求密鑰文件解密。這套機(jī)制能防住直接下載分片拼接但密鑰一旦泄露保護(hù)便失效所以實(shí)際部署要注意密鑰接口的訪(fǎng)問(wèn)權(quán)限控制。4. m3u8 轉(zhuǎn)回 mp4拉流合并、超時(shí)控制與本地文件的差異處理4.1 最簡(jiǎn)單的合并命令與-c copy的適用條件ffmpeg -i https://example.com/path/playlist.m3u8 \ -c copy \ -bsf:a aac_adtstoasc \ output.mp4-c copy表示不重新編碼直接把 ts 分片里的視頻幀和音頻幀搬運(yùn)到 mp4 容器中。這個(gè)過(guò)程非常快但有兩個(gè)前提所有分片的編碼格式必須一致且音頻必須是 AAC。如果源 m3u8 里音頻是 MP3 或 AC-3-c copy生成的 mp4 在部分播放器里識(shí)別不了這時(shí)去掉-c copy改為-c:v copy -c:a aac只重編碼音頻。-bsf:a aac_adtstoasc是 m3u8 轉(zhuǎn) mp4 的一個(gè)關(guān)鍵參數(shù)。ts 里的 AAC 音頻是 ADTS 流格式mp4 要求的是 ASC 配置格式不加這個(gè)參數(shù)轉(zhuǎn)換出來(lái)的 mp4 音頻在 QuickTime、部分安卓播放器里會(huì)靜音。備份習(xí)慣如果直接-c copy失敗優(yōu)先加這一項(xiàng)重試。4.2 網(wǎng)絡(luò) m3u8 容易失敗超時(shí)、斷流和重連參數(shù)拉網(wǎng)絡(luò)流和轉(zhuǎn)本地文件完全是兩回事。m3u8 的每個(gè)分片都是一次獨(dú)立的 HTTP 請(qǐng)求任意一個(gè)分片超時(shí)或 404ffmpeg 就可能直接中斷。給網(wǎng)絡(luò)流加超時(shí)與重試參數(shù)ffmpeg -i https://example.com/path/playlist.m3u8 \ -timeout 15 \ -rw_timeout 15000000 \ -c copy \ -bsf:a aac_adtstoasc \ output.mp4-timeout是 TCP 連接超時(shí)單位秒-rw_timeout是讀寫(xiě)超時(shí)單位微秒。15000000 微秒即 15 秒意味著單個(gè)分片在 15 秒內(nèi)沒(méi)有傳輸完成就會(huì)判定失敗。某些 CDN 響應(yīng)慢但不超時(shí)單個(gè) ts 可能會(huì)拖幾百秒這時(shí)-rw_timeout比-timeout更管用。遇到403 Forbidden或404 Not Found先檢查 m3u8 里的分片路徑是相對(duì)路徑還是絕對(duì)路徑。有些 CDN 的訪(fǎng)問(wèn)需要攜帶 Referer 或 User-Agent用-headers Referer: https://example.com/補(bǔ)上請(qǐng)求頭。如果索引文件還需要 cookie可以用-cookies namevalue; name2value2。4.3 本地 m3u8 與網(wǎng)絡(luò) m3u8 的協(xié)議白名單差異ffmpeg 對(duì)不同協(xié)議有白名單限制。轉(zhuǎn)本地 m3u8 時(shí)默認(rèn)允許file協(xié)議但某些自編譯版本會(huì)拒絕讀取非白名單協(xié)議。報(bào)錯(cuò)形如Protocol https not on whitelist file,crypto,data需要顯式聲明允許的協(xié)議ffmpeg -protocol_whitelist file,http,https,tcp,tls,crypto \ -i https://example.com/path/playlist.m3u8 \ -c copy output.mp4crypto是解密 AES-128 分片時(shí)必須的協(xié)議不加它遇到帶#EXT-X-KEY的 m3u8 會(huì)報(bào)Failed to open key。本地 m3u8 如果引用相對(duì)路徑只寫(xiě)file就夠了。注意這個(gè)參數(shù)要放在-i之前才會(huì)生效寫(xiě)在輸出側(cè)會(huì)被當(dāng)作輸出選項(xiàng)而忽略。4.4 合并過(guò)程中的時(shí)間戳異常與音頻延遲網(wǎng)絡(luò) m3u8 經(jīng)常存在分片之間的時(shí)間戳不連續(xù)比如某個(gè) ts 的 PTS 忽然跳變合并后 mp4 的表現(xiàn)是畫(huà)面卡頓或音畫(huà)不同步。排查時(shí)先逐段檢查每個(gè)分片for f in seg_*.ts; do ffprobe -v error -show_entries formatduration -of csvp0 $f done輸出每個(gè)分片的時(shí)長(zhǎng)列表對(duì)比 m3u8 里#EXTINF的對(duì)應(yīng)值。偏差超過(guò) 0.5 秒的單獨(dú)重編碼該分片再合并。如果整體音頻延遲固定用-af adelay200|200給音頻加 200ms 延遲或者用-itsoffset 0.2 -i給整個(gè)輸入做時(shí)間偏移。多數(shù)音畫(huà)不同步不是編碼問(wèn)題而是源分片本身的時(shí)間戳就亂了。5. ffpreset 預(yù)設(shè)文件的加載機(jī)制與條件化轉(zhuǎn)碼腳本設(shè)計(jì)5.1 ffpreset 是什么一套按行讀取的文本參數(shù)文件ffpreset 是 ffmpeg 自帶的一種參數(shù)預(yù)設(shè)機(jī)制文件名后綴為.ffpreset。它的加載方式有兩種-vpre name會(huì)去 ffmpeg 編譯時(shí)指定的預(yù)設(shè)目錄里找libx264-name.ffpreset-fpre /path/to/file.ffpreset則直接按絕對(duì)路徑加載。ffmpeg 官方分發(fā)版內(nèi)置了libx264-ipod320.ffpreset、libx264-ipod640.ffpreset等適用于移動(dòng)設(shè)備兼容的預(yù)設(shè)文件但數(shù)量很少實(shí)際使用中更常見(jiàn)的是自己寫(xiě)一套。ffpreset 文件內(nèi)容長(zhǎng)這樣# 這是注釋以#開(kāi)頭 vcodeclibx264 acodecaac crf22 presetmedium profilehigh level4.0每行一個(gè)輸出參數(shù)等號(hào)左邊是 ffmpeg 的選項(xiàng)名右邊是值。-fpre會(huì)將文件中的所有keyvalue按序應(yīng)用到輸出流上等價(jià)于在命令行逐項(xiàng)手寫(xiě)。常用于固定一批測(cè)試環(huán)境和生產(chǎn)環(huán)境共用的編碼基線(xiàn)避免有人在命令行里加奇怪的參數(shù)導(dǎo)致產(chǎn)物不一致。5.2-fpre與命令行參數(shù)、-preset的關(guān)系ffmpeg 處理參數(shù)的順序是從左到右后出現(xiàn)的同類(lèi)參數(shù)會(huì)覆蓋先出現(xiàn)的。-fpre preset.ffpreset寫(xiě)在輸出文件前等同展開(kāi)為對(duì)應(yīng)選項(xiàng)如果在-fpre之后再寫(xiě)-crf 18則crf22被覆蓋為 18。這個(gè)順序特性常被用來(lái)做「預(yù)設(shè)打底 個(gè)別覆蓋」比直接拼命令行更可維護(hù)。需要特別區(qū)分-preset medium和-fpre xxx.ffpreset-preset是 libx264 編碼器內(nèi)部的速度檔位只有編碼器是 libx264 時(shí)才生效-fpre是 ffmpeg 層面的參數(shù)組合里面可以放任意編碼器參數(shù)。實(shí)際使用中可以在 ffpreset 里寫(xiě)presetslower從而把兩層統(tǒng)一管理。5.3 按源視頻條件選擇預(yù)設(shè)ffprobe 判斷加 ffpreset 執(zhí)行condition字面意思是條件。ffmpeg 本身沒(méi)有內(nèi)置「如果視頻分辨率大于某值則用某預(yù)設(shè)」的條件表達(dá)式條件分支要放在預(yù)設(shè)加載之前用腳本判斷。以下是一段 bash 腳本示例#!/bin/bash input$1 # 讀取視頻分辨率 width$(ffprobe -v error -select_streams v:0 -show_entries streamwidth -of csvp0 $input) # 讀取視頻時(shí)長(zhǎng)單位秒浮點(diǎn) duration$(ffprobe -v error -show_entries formatduration -of csvp0 $input) # 判斷分辨率與時(shí)長(zhǎng)選擇不同預(yù)設(shè) if [ $width -ge 1920 ] || (( $(echo $duration 600 | bc -l) )); then preset_file./preset_1080p_vod.ffpreset hls_time8 else preset_file./preset_small.ffpreset hls_time4 fi ffmpeg -i $input \ -fpre $preset_file \ -hls_time $hls_time -hls_list_size 0 \ -hls_playlist_type vod \ output_$(basename ${input%.mp4}).m3u8判斷邏輯把兩個(gè)常見(jiàn)業(yè)務(wù)條件拆開(kāi)分辨率大于等于 1920 或者時(shí)長(zhǎng)超 600 秒走高清長(zhǎng)切片預(yù)設(shè)否則走小體積短切片預(yù)設(shè)。bc用于浮點(diǎn)比較如果你的設(shè)備環(huán)境沒(méi)有裝 bc可以用awk -v a$duration BEGIN{exit !(a600)}代替。這里的核心思想是把「判斷」和「執(zhí)行」分開(kāi)條件決定選哪份預(yù)設(shè)預(yù)設(shè)只描述編碼參數(shù)。5.4 兩份預(yù)設(shè)文件的業(yè)務(wù)設(shè)計(jì)和常見(jiàn)誤區(qū)預(yù)設(shè)文件不是越全越好。推薦按業(yè)務(wù)維度拆分而不是按編碼器維度拆分比如preset_1080p_vod.ffpreset、preset_720p_clip.ffpreset里面包含分辨率縮放、碼率檔位和 profile 設(shè)置這樣條件腳本看起來(lái)一目了然。preset_1080p_vod.ffpreset實(shí)例vcodeclibx264 acodecaac crf20 presetslow profilehigh level4.2 vfscale-2:1080 r30vfscale-2:1080把視頻統(tǒng)一縮放到高 1080寬度按比例自動(dòng)計(jì)算-2保證數(shù)值是偶數(shù)避免 YUV 采樣報(bào)錯(cuò)。r30強(qiáng)制幀率為 30fps防止源視頻 29.97 與輸出時(shí)間戳產(chǎn)生累積誤差。常見(jiàn)誤區(qū)是把容器選項(xiàng)寫(xiě)進(jìn) ffpreset例如在文件里寫(xiě)hls_time6或fmp4。-fpre只會(huì)把參數(shù)應(yīng)用到編碼流上不會(huì)應(yīng)用到容器封裝層所以hls_time、f這類(lèi)選項(xiàng)寫(xiě)進(jìn)去會(huì)被忽略。要控制切片參數(shù)的仍然放在命令行用變量把條件腳本里算出的hls_time傳進(jìn)去。另一個(gè)誤區(qū)是預(yù)設(shè)里隨意寫(xiě) level 值profile 為 high 時(shí)搭配過(guò)低的 level 會(huì)直接報(bào)Unsupported resolution需要互相匹配。6. 快速驗(yàn)證 m3u8 轉(zhuǎn)碼結(jié)果的三板斧看錯(cuò)誤、看參數(shù)、看播放6.1 用ffmpeg -v error過(guò)濾真正影響輸出的問(wèn)題轉(zhuǎn)碼日志幾千行沒(méi)必要逐行看。-v error只輸出真正的錯(cuò)誤忽略警告和調(diào)試信息ffmpeg -v error -i input.mp4 -c copy -bsf:a aac_adtstoasc out.mp4如果輸出為空說(shuō)明文件基本正常。結(jié)合-v warning能看到非致命問(wèn)題比如時(shí)間戳不連續(xù)、非標(biāo)準(zhǔn)幀率、元數(shù)據(jù)缺失。批處理轉(zhuǎn)碼時(shí)把錯(cuò)誤輸出到獨(dú)立日志文件再按行統(tǒng)計(jì)是快速定位批量失敗的最有效手段。6.2 用 ffprobe 驗(yàn)證切片均勻性和 m3u8 完整性轉(zhuǎn)碼完成后驗(yàn)證的環(huán)節(jié)不能省# 驗(yàn)證源視頻信息 ffprobe -v error -show_streams -show_format output.m3u8 # 統(tǒng)計(jì)所有分片時(shí)長(zhǎng)偏差 for f in seg_*.ts; do ffprobe -v error -show_entries formatduration -of csvp0 $f done | awk {sum$1; if(NR1){min$1;max$1}; if($1min)min$1; if($1max)max$1} END {printf 分片數(shù): %d, 平均: %.2f, 最小: %.2f, 最大: %.2f\n, NR, sum/NR, min, max}理想情況下最長(zhǎng)的分片和最短的分片差距不超過(guò) 2 秒。如果出現(xiàn)單個(gè)分片時(shí)長(zhǎng)異常長(zhǎng)多半是源視頻的關(guān)鍵幀間隔設(shè)置有問(wèn)題需要回到編碼參數(shù)調(diào)整keyint而不是在切片階段找原因。m3u8 轉(zhuǎn)換是編碼和封裝的綜合產(chǎn)物分片時(shí)長(zhǎng)是否均勻可以直接反映源視頻的編碼質(zhì)量。6.3 最后一根救命稻草拆成最小可復(fù)現(xiàn)命令遇到奇怪的問(wèn)題不要在一長(zhǎng)串命令上反復(fù)調(diào)整。習(xí)慣是把命令縮到最短ffmpeg -i output.m3u8 -t 10 out.mp4只轉(zhuǎn)前 10 秒去掉-c copy去掉所有預(yù)設(shè)看問(wèn)題是否存在。如果最小命令正常再逐步加回參數(shù)直到定位到是哪個(gè)參數(shù)引發(fā)的故障。這個(gè)方法在處理「m3u8 轉(zhuǎn) MP4 失敗」和「mp4 轉(zhuǎn) m3u8 播放卡頓」這兩類(lèi)問(wèn)題時(shí)都比查日志更快因?yàn)樗炎兞恐饌€(gè)排除而不是盲試。ffmpeg 的行為沒(méi)有魔法每一個(gè)報(bào)錯(cuò)都能在這套最小復(fù)現(xiàn)方法里被壓縮成一個(gè)可控實(shí)驗(yàn)。本文還有配套的精品資源點(diǎn)擊獲取