如何無損地將資料傳輸到 FFmpeg 或從 FFmpeg 傳輸資料?

如何無損地將資料傳輸到 FFmpeg 或從 FFmpeg 傳輸資料?

我將流從一個 FFmpeg 實例通過管道傳輸到另一個實例,但由於中間流使用了壓縮,因此最終結果很醜陋。我需要一個無損管道來防止這種情況,並且我希望它包含音訊和視訊。

我懷疑這個問題有不止一個答案,因此任何提供詳盡解決方案清單(可以透過管道傳輸的兼容容器和編解碼器)的人都會獲得加分。任何解釋其他數據(例如字幕)的人也可以獲得獎勵積分。

編輯:我正在尋找合適的編解碼器/容器組合。我不知道為什麼人們很難弄清楚這一點,因為我說我已經使用了管道,現在我需要它是無損的。

我不知道如何解釋這一點而不聽起來自負,但這是一個常見問題解答網站。提出需要極其具體答案的問題不會對透過將自己的問題輸入搜尋引擎而訪問該網站的數百萬用戶有所幫助。我的問題旨在幫助任何需要在FFmpeg 實例之間無損傳輸資料的人,而不用一堵敘述性和程式碼解釋我在做什麼、為什麼它不起作用以及為什麼這是唯一的選擇來分散每個人的注意力。

答案1

如何無損地傳輸視訊和ffmpeg音頻ffmpeg

提問者的要求:

  • 無損地從一個實例傳送ffmpeg到另一個實例
  • 往返都沒關係/dev/null

例子:

ffmpeg -s 1280x720 -f rawvideo -i /dev/zero -ar 48000 -ac 2 -f s16le -i \
/dev/zero -c copy -f nut pipe:1 | ffmpeg -y -i pipe:0 -c copy -f nut /dev/null

我看不出有人會這樣做。此外,當您很可能只使用一個進程來做任何您想做的事情時,幾乎沒有理由通過管道從ffmpeg到。ffmpegffmpeg

選項的作用:

  • -s 1280x720 -f rawvideo– 描述輸入的選項/dev/zero不是典型的輸入格式,因此需要這些附加選項。

  • -i /dev/zero– 視訊輸入。在此範例中,它用於從“無”生成視訊串流。範例中使用了這一點,因為提問者拒絕提供有關所使用的輸入的任何資訊。

  • -ar 48000 -ac 2 -f s16le– 描述輸入的選項/dev/zero不是典型的音訊格式。

  • -i /dev/zero– 音訊輸入。在此範例中,它用於從“無”生成音訊串流。

  • -c copy串流複製,或重新重複使用,輸入到輸出。沒有執行重新編碼,因此該過程是無損的。未知提問者是否可以接受流複製。也許需要重新編碼?

  • -f nut– 您需要告訴ffmpeg管道使用什麼格式。 Nut 是一種容器格式。請參閱ffmpeg -formats參考資料 以取得完整清單。另一種靈活的格式是-f matroska,但如果沒有提問者提供更多信息,就不可能建議使用適當或特定的輸出容器格式。

  • pipe:1- 使用pipe協定輸出到標準輸出。或者,可以省略該數字(僅pipe:),預設情況下,stdout 檔案描述符將用於寫入,stdin 將用於讀取。

答案2

我學到的方法(從先前答案的部分內容)是使用rawvideo視訊編解碼器、pcm_s16le音訊編解碼器和 FFmpeg 的nut包裝器來對串流進行編碼。nutFFmpeg 之外的主要程式不支持,但它是我目前所知的唯一可以支援在進程之間有效傳輸資料所需的未壓縮格式的容器。

此編碼的參數可能如下所示:

... -c:v rawvideo -c:a pcm_16le -f nut - ...

某些音訊以 24 位元或更大的樣本存儲,對於這些樣本,您應該使用pcm_24le或其他格式。運行時將列出未壓縮音訊格式的完整清單ffmpeg -codecs(您必須在清單中搜尋它們)。如果您不知道音訊的樣本大小是多少,那麼使用pcm_16le應該不會造成明顯的品質損失。

在管道的接收端,將輸入設定為標準輸入,ffmpeg 將偵測格式並解碼流。

... ffmpeg -i - ...

此答案中的省略號 (...) 不是代碼的一部分。這些就是您的程式碼所在的位置。單獨的連字符 (-) 告訴 FFmpeg 使用標準輸入或標準輸出,取決於它們出現的位置。

更新:

我嘗試了一個簡單的實驗來改進這一點,似乎更好的容器是AVI,因為其他程式會理解它(至少VLC會)。

... -c:v rawvideo -c:a pcm_16le -f avi - ...

這將像舊版本一樣工作,並具有額外的兼容性。

事後看來,我很遺憾發布了一個在許多情況下沒有幫助的問題,儘管我聲稱問題應該對每個人都有幫助。這使得答案更有用。

答案3

另一個答案的一個問題是它是 pcm_s16le,而不是 s16le。此外,它還包含許多冗餘參數。

我會在管道中使用 pcm 而不是 flac,因為處理時間要少得多(PCM 是原始音頻,FLAC 需要大量時間來編碼)。

不管怎樣,我會這樣做。

ffmpeg -i <input video file/stream> -vcodec rawvideo -acodec pcm_s16le pipe:1 | ffmpeg -f rawvideo -i - -vcodec <video output codec> -acodec <audio output codec> -vb <video bitrate if applicable> -ab <audio bitrate if applicable> <final-output-filename>

當我上次嘗試時,這對我有用,但我的目標是將 ffmpeg 通過管道傳輸到 ffplay,這是一個略有不同的過程。

例子:

這會將視訊從 ffmpeg 傳輸到另一個實例作為原始視訊輸出和 16 位元小端 PCM(兩者都是無損的,除非您有 24 位元 PCM,然後替換pcm_s24le。)然後在第二個實例中使用fraunhoefer 將它們轉換為h.264來自 Android 專案的 AAC 函式庫(libfaac更常見於 ffmpeg 建置中。您可以用它取代它。)

ffmpeg -i montypythonsflyingcircus-s1e1.avi -vcodec rawvideo -acodec pcm_s16le pipe:1 | ffmpeg -i - -vcodec libx264 -acodec libfdk_aac -vb 1200k -ab 96k mpfc-s1e01-output.mkv

如果這不能透過管道傳送字幕,您可以隨時將它們翻錄為 SRT,然後將其混合回來,或者輕鬆地將它們添加到上面的管道中。

相關內容