【💊 Python的解憂錦囊】使用python-ffmpeg即時串流轉換音檔格式

閱讀時間約 6 分鐘

訊息的即時傳遞已然成為現代社會的趨勢了, 影音也是如此, 即時! 即時! 即時! 已經是目前使用者體驗的必要元素了, 在這邊我們要分享的主題是如何在python程式語言的情境下使用ffmpeg來將音檔串流的轉換格式, 為什麼會有這樣的需求呢? 因為我們處理音檔時可能會需要統一輸出的格式, 當然背後也是考量到成本、效率兩大因素, 檔案越小越好, 節省的硬體成本可以提昇企業的獲利, 而搭上「串流」的應用我們可以怎麼處理音訊的部份呢?


那麼我們今天的demo概念流程如下:

raw-image


預期會設計一個讀取器, 一包一包的讀取來源音檔, 並透過python-ffmpeg轉碼, 轉換成指定的音檔格式, 最後將轉換後的封包組合並輸出成檔案。


程式碼分析與實作

這邊是我們實際運作後可行的程式碼:

import ffmpeg
import io
import os
import queue
import threading

def read_output(pipe, q):
""" 用於非阻塞讀取 ffmpeg 的 stdout """
while True:
data = pipe.read(4096)
if not data:
break
q.put(data)
q.put(None) # 標記輸出結束

def convert(input_file_path, output_file_path):
# 打開原始文件
with open(input_file_path, 'rb') as input_file:
# 創建一個 BytesIO 物件來處理轉換的輸出
output_stream = io.BytesIO()

# 使用 ffmpeg 進行轉換
process = (
ffmpeg
.input('pipe:0') # 從標準輸入讀取
.output('pipe:1', format='wav') # 輸出到標準輸出,格式為 opus
.run_async(pipe_stdin=True, pipe_stdout=True, pipe_stderr=True)
)

# 創建一個隊列來接收標準輸出
q = queue.Queue()
# 啟動一個線程來讀取標準輸出
threading.Thread(target=read_output, args=(process.stdout, q), daemon=True).start()

# 逐段讀取並寫入轉換過程
chunk_size = 4096
while True:
chunk = input_file.read(chunk_size)
if not chunk:
break
process.stdin.write(chunk)

# 關閉標準輸入流
process.stdin.close()

# 讀取轉換過來的數據並寫入 BytesIO 物件
while True:
out_chunk = q.get()
if out_chunk is None:
break
output_stream.write(out_chunk)

# 確保 process 結束
process.wait()

# 將 BytesIO 物件的內容寫入到指定的輸出文件中
with open(output_file_path, 'wb') as output_file:
output_file.write(output_stream.getvalue())

# 使用範例
convert('2.mp3', '2.wav')


接著我們用圖來分析一下上述的實作範例:

raw-image

📌 關鍵重點如下:

  1. 多執行緒分別處理標準輸出與輸入。
  2. 由queue搭起ffmpeg輸出與輸入的執行緒溝通橋樑。


讓我們來檢視一下轉換前/後

我們轉出後會有以下的音檔:

raw-image



接著我們使用ffprobe來檢查這兩個檔案:


ffprobe examples/2.mp3

....
Input #0, mp3, from '2.mp3':
Metadata:
Encoded by : LAME in FL Studio 20
BPM (beats per minute): 120
date : 2018
Duration: 00:00:58.02, start: 0.025057, bitrate: 146 kb/s
Stream #0:0: Audio: mp3, 44100 Hz, stereo, fltp, 146 kb/s
Metadata:
encoder : LAME3.100
ffprobe examples/2.wav

...
Input #0, wav, from '2.wav':
Metadata:
date : 2018
encoder : Lavf59.27.100
Duration: 00:00:57.99, bitrate: 1411 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, 2 channels, s16, 1411 kb/s



結語

我們的分享僅將格式進行粗淺的轉換, 更多細部的參數調整還是需要您自行對ffmpeg進行設定, 這部份只是在講述如何將小封包流過ffmpeg再流到檔案的過程, 對了, 如果您對於串流應用感到興趣,也歡迎您加入「🔒 阿Han的軟體心法實戰營 - kafka專區」, 讓我們一起為「串流」的資要搭起橋樑, 讓傳輸更即時可靠。

116會員
257內容數
哈囉,我是阿Han,是一位 👩‍💻 軟體研發工程師,喜歡閱讀、學習、撰寫文章及教學,擅長以圖代文,化繁為簡,除了幫助自己釐清思路之外,也希望藉由圖解的方式幫助大家共同學習,甚至手把手帶您設計出高品質的軟體產品。
留言0
查看全部
發表第一個留言支持創作者!
阿Han的沙龍 的其他內容
我們在學習kafka的過程中最不習慣的就是不管什麼樣的資料, 在kafka的傳輸過程都會是binary的資料格式, 因此我們在撰寫程式的過程中並不是那麼的直觀, 必須將資料從float、int…資料型態轉型成binary才能順利傳送, 那麼基於這樣的前提之下, python這套程式語言可以怎麼做
情境描述 我們在「🔒 阿Han的軟體心法實戰營 - kafka」有關於kafka的教學文章, 那麼在開發過程中我們遇到了 👻 詭異事件, 那就是我們嘗試在做一個檔案串流時, 發現Producer明明傳送了大約16MB檔案大小的封包到kafka, 每一包約(1024 * 1024 ) bytes
更快、更短、更即時是串流傳輸必要的元素, 而我們常常在使用Python請求API時都是等待式回應, 也就是一個請求過去之後, 待對方處理完畢後再行回應, 但假設需要下載的檔案、內容非常大時, 是不是使用者只能傻傻的等待整個傳輸結束後才能顯示? 這樣的使用者體驗也實在太糟糕了, 對於使用者來說除了完全
情況描述 我們在「【🔒 Python 先修班】教你親手打包專屬套件庫的手作課(pip install…)」有提到如何打包Python讓自己的程式變成套件, 讓其他人可以用pip install的方式進行安裝,😲 But… 我們實際上打包後, 發現到引用的檔案都有被打包進去,但目錄卻未被打包
我們在「【🔒 Python API框架篇 - FastAPI】Ep.1 啟航」有分享 FastAPI 這套API框架, 那麼當我們想要在應用程式剛執行時就註冊一些事件或者共享GPU運算模型、變數…等,當整個應用程式關閉時也進行釋放作業, 這樣的一個週期循環就是所謂的生命週期, 而在FastAPI這
當我們在開發一個AI應用服務時, 常常會需要載入大模型, But… 我們總不可能每一次的請求就載入一次模型吧! 這樣太沒有效率了, 也非常的浪費資源, 因此我們通常會希望應用程式啟動時就能夠載入模型, 之後每一次的請求只要讓模型進行運算即可, 那麼在FastAPI的框架中究竟要如何使用呢? 首
我們在學習kafka的過程中最不習慣的就是不管什麼樣的資料, 在kafka的傳輸過程都會是binary的資料格式, 因此我們在撰寫程式的過程中並不是那麼的直觀, 必須將資料從float、int…資料型態轉型成binary才能順利傳送, 那麼基於這樣的前提之下, python這套程式語言可以怎麼做
情境描述 我們在「🔒 阿Han的軟體心法實戰營 - kafka」有關於kafka的教學文章, 那麼在開發過程中我們遇到了 👻 詭異事件, 那就是我們嘗試在做一個檔案串流時, 發現Producer明明傳送了大約16MB檔案大小的封包到kafka, 每一包約(1024 * 1024 ) bytes
更快、更短、更即時是串流傳輸必要的元素, 而我們常常在使用Python請求API時都是等待式回應, 也就是一個請求過去之後, 待對方處理完畢後再行回應, 但假設需要下載的檔案、內容非常大時, 是不是使用者只能傻傻的等待整個傳輸結束後才能顯示? 這樣的使用者體驗也實在太糟糕了, 對於使用者來說除了完全
情況描述 我們在「【🔒 Python 先修班】教你親手打包專屬套件庫的手作課(pip install…)」有提到如何打包Python讓自己的程式變成套件, 讓其他人可以用pip install的方式進行安裝,😲 But… 我們實際上打包後, 發現到引用的檔案都有被打包進去,但目錄卻未被打包
我們在「【🔒 Python API框架篇 - FastAPI】Ep.1 啟航」有分享 FastAPI 這套API框架, 那麼當我們想要在應用程式剛執行時就註冊一些事件或者共享GPU運算模型、變數…等,當整個應用程式關閉時也進行釋放作業, 這樣的一個週期循環就是所謂的生命週期, 而在FastAPI這
當我們在開發一個AI應用服務時, 常常會需要載入大模型, But… 我們總不可能每一次的請求就載入一次模型吧! 這樣太沒有效率了, 也非常的浪費資源, 因此我們通常會希望應用程式啟動時就能夠載入模型, 之後每一次的請求只要讓模型進行運算即可, 那麼在FastAPI的框架中究竟要如何使用呢? 首
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
11/20日NVDA即將公布最新一期的財報, 今天Sell Side的分析師, 開始調高目標價, 市場的股價也開始反應, 未來一週NVDA將重新回到美股市場的焦點, 今天我們要分析NVDA Sell Side怎麼看待這次NVDA的財報預測, 以及實際上Buy Side的倉位及操作, 從
Thumbnail
Hi 大家好,我是Ethan😊 相近大家都知道保濕是皮膚保養中最基本,也是最重要的一步。無論是在畫室裡長時間對著畫布,還是在旅途中面對各種氣候變化,保持皮膚的水分平衡對我來說至關重要。保濕化妝水不僅能迅速為皮膚補水,還能提升後續保養品的吸收效率。 曾經,我的保養程序簡單到只包括清潔和隨意上乳液
Thumbnail
在 Python 中,print( ) 函數用於將結果輸出到螢幕上。當你嘗試將不同資料型別(例如字串和數字)混合在一起輸出時,print( )函數無法直接處理這些不同型別的資料,因此你需要先將它們轉換為相同的資料型別。通常,這意味著需要將數字轉換為字串型別,以便與其他字串一同輸出。 雖然我們也可以
Thumbnail
我們在學習kafka的過程中最不習慣的就是不管什麼樣的資料, 在kafka的傳輸過程都會是binary的資料格式, 因此我們在撰寫程式的過程中並不是那麼的直觀, 必須將資料從float、int…資料型態轉型成binary才能順利傳送, 那麼基於這樣的前提之下, python這套程式語言可以怎麼做
Thumbnail
本文利用pyqt5,使用pyttsx3將QLineEdit(單行輸入框)的字串,轉成語音呈現出來。
Thumbnail
更快、更短、更即時是串流傳輸必要的元素, 而我們常常在使用Python請求API時都是等待式回應, 也就是一個請求過去之後, 待對方處理完畢後再行回應, 但假設需要下載的檔案、內容非常大時, 是不是使用者只能傻傻的等待整個傳輸結束後才能顯示? 這樣的使用者體驗也實在太糟糕了, 對於使用者來說除了完全
Thumbnail
我們在「【🎓 Python的深度問答集】torchaudio 對部分段落進行音訊解碼」有分享到如何對一包包的封包進行音訊解碼, 但隨著音檔越大, 最終解碼的速度會越來越慢, 而這並非串流的本意, 串流應該就像水管一樣, 收到多少資料就運算多少量, 並不會隨著累積的容量越大而導致效能下降。 但實際
Thumbnail
torchaudio 是 PyTorch 的官方音訊處理庫,提供了許多用於音訊數據讀取、轉換和處理的工具和功能。它旨在簡化音訊數據的加載、預處理和後續處理過程,同時與 PyTorch 緊密整合, 包括我們常常用於資料科學處理的Tensor資料。 這個篇章主要在分享我們如何使用標準的I/O進行讀
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
11/20日NVDA即將公布最新一期的財報, 今天Sell Side的分析師, 開始調高目標價, 市場的股價也開始反應, 未來一週NVDA將重新回到美股市場的焦點, 今天我們要分析NVDA Sell Side怎麼看待這次NVDA的財報預測, 以及實際上Buy Side的倉位及操作, 從
Thumbnail
Hi 大家好,我是Ethan😊 相近大家都知道保濕是皮膚保養中最基本,也是最重要的一步。無論是在畫室裡長時間對著畫布,還是在旅途中面對各種氣候變化,保持皮膚的水分平衡對我來說至關重要。保濕化妝水不僅能迅速為皮膚補水,還能提升後續保養品的吸收效率。 曾經,我的保養程序簡單到只包括清潔和隨意上乳液
Thumbnail
在 Python 中,print( ) 函數用於將結果輸出到螢幕上。當你嘗試將不同資料型別(例如字串和數字)混合在一起輸出時,print( )函數無法直接處理這些不同型別的資料,因此你需要先將它們轉換為相同的資料型別。通常,這意味著需要將數字轉換為字串型別,以便與其他字串一同輸出。 雖然我們也可以
Thumbnail
我們在學習kafka的過程中最不習慣的就是不管什麼樣的資料, 在kafka的傳輸過程都會是binary的資料格式, 因此我們在撰寫程式的過程中並不是那麼的直觀, 必須將資料從float、int…資料型態轉型成binary才能順利傳送, 那麼基於這樣的前提之下, python這套程式語言可以怎麼做
Thumbnail
本文利用pyqt5,使用pyttsx3將QLineEdit(單行輸入框)的字串,轉成語音呈現出來。
Thumbnail
更快、更短、更即時是串流傳輸必要的元素, 而我們常常在使用Python請求API時都是等待式回應, 也就是一個請求過去之後, 待對方處理完畢後再行回應, 但假設需要下載的檔案、內容非常大時, 是不是使用者只能傻傻的等待整個傳輸結束後才能顯示? 這樣的使用者體驗也實在太糟糕了, 對於使用者來說除了完全
Thumbnail
我們在「【🎓 Python的深度問答集】torchaudio 對部分段落進行音訊解碼」有分享到如何對一包包的封包進行音訊解碼, 但隨著音檔越大, 最終解碼的速度會越來越慢, 而這並非串流的本意, 串流應該就像水管一樣, 收到多少資料就運算多少量, 並不會隨著累積的容量越大而導致效能下降。 但實際
Thumbnail
torchaudio 是 PyTorch 的官方音訊處理庫,提供了許多用於音訊數據讀取、轉換和處理的工具和功能。它旨在簡化音訊數據的加載、預處理和後續處理過程,同時與 PyTorch 緊密整合, 包括我們常常用於資料科學處理的Tensor資料。 這個篇章主要在分享我們如何使用標準的I/O進行讀