正確修復使用舊版 x264 編碼的視頻

正確修復使用舊版 x264 編碼的視頻

由於舊版 x264 的 bug,h.264 視訊串流具有以下三個屬性:

  1. 使用 x264 build 150 或更早版本編碼
  2. 使用 4:4:4 色度子取樣
  3. 位元流不包含 x264 版本信息

許多視訊播放器無法正常播放。新版本的視訊播放器mpv有一個專用選項

--vd-lavc-assume-old-x264

專門解決這個問題(請參閱:https://mpv.io/manual/master/)。

FFmpeg 錯誤追蹤器建議將正確的 SEI.h264 新增至視訊串流(我猜包含 x264 版本資訊)。我不想依賴這樣的駭客,所以我的問題是:是否有一種「正確」的方法(最好使用 ffmpeg)來修復文件,就好像它們首先是用新的(固定)版本的 x264 進行編碼的一樣

顯然我想保留(或多或少)視頻品質文件大小。如果需要重新編碼,那麼除了修復舊 x264 實現的錯誤行為之外,它應該什麼也不改變。 (更多資訊:錯誤報告給出了一個損壞文件的範例。據推測,舊x264中的錯誤可能是這裡介紹.)

答案1

感謝您提出這個問題,它也幫助我了解了我遇到的問題的本質。我有一個似乎有效的解決方案。

就我而言,我使用 Ubuntu 儲存庫中的 ffmpeg。能夠解碼我的 libx264 檔案的最後一個版本是 2.8.6。升級到 2.8.14 或 2.8.15 後,我遇到了您描述的解碼問題。我不想重新編碼我的舊視頻,我只是想修復標頭,以便 ffmpeg 可以正確識別原始編碼期間引入的錯誤,並正確播放它們。

所以首先我下載包含最新版本 ffmpeg v4 的靜態二進位文件。我將此二進位檔案連結到ffmpeg4我的系統上,以便我可以控制我正在使用的版本。我們需要一些2.8之後引入的新功能(不太確定是什麼時候)。如果您已經安裝了較新版本的 ffmpeg,只需使用它並在下面的命令中替換ffmpeg4為。ffmpeg

現在,從損壞的影片中提取原始位元流(將其稱為 BROKEN.mkv)。

ffmpeg4 -i BROKEN.mkv -vcodec copy -an -bsf:v h264_mp4toannexb raw.h264

我不確定 h264_mp4toannexb 標誌是否必要,它可能會自動插入對於這種格式。

現在,將位元流放入新的 mp4 容器中,並修復 SEI 標頭中有關舊有 bug 的 x264 版本的信息

ffmpeg4 -r 30 -i raw.h264 -avoid_negative_ts 1 -bsf:v h264_metadata='sei_user_data=dc45e9bde6d948b7962cd820d923eeef+x264 - core 150' -c copy FIXED.mp4

位元流不包含時間戳訊息,因此您將在這裡收到大量警告。我還發現我必須手動將幀速率設定為 30fps ( -r 30),否則它會猜測 25 到 30fps 之間的一些可變幀速率。我不知道如何正確提取時間戳記或將它們正確混合到新容器中。如果您有解決辦法,請告訴我!很多人推薦,-fflags +genpts但這不似乎做任何事為我。最後,我添加了-avoid_negative_ts 1為了使第一幀的時間戳為非負數。

最後,這是可選的,如果您想將結果放入 MKV 容器中,您可以這樣做

ffmpeg4 -i FIXED.mp4 -c copy FIXED.mkv

為什麼先轉換為 MP4,然後再轉換為 MKV?看起來 MKV 容器會簡單地拒絕在沒有時間戳的情況下繼續進行,但 MP4 會這樣做並只是發出警告。然後您可以轉換為 MKV 而不會出現警告。

完成所有這些之後,我有了可用的 MP4 和 MKV 檔案。然而,我檢查了一些幀,發現有一些細微的變化(亮度變化約為 2 個等級)。我不明白為什麼會發生這種情況,因為這應該是無損的。如果您對如何做得更好有任何建議,請告訴我。

編輯:我注意到 MP4 容器中的一些時間戳為負數,從 -0.066667s 開始。轉移到 MKV 容器後,所有負時間戳都變成零。添加-output_ts_offset 0.066667到命令修復了這個問題並讓它們從零開始。我不明白為什麼它從 -0.066667 開始。

編輯 2:刪除負時間戳記的更好方法是在編碼 mp4 時使用“-avoid_negative_ts 1”。

相關內容