我正在建立一個 icecast2 廣播電臺,它將以較低的質量重新播放現有電臺。該程式將生成多個 FFmpeg 行程 24/7 重新流式傳輸。出于故障排除的目的,我希望將每個 FFmpeg 行程的輸出重定向到單獨的檔案。
import ffmpeg, csv
from threading import Thread
def run(name, mount, source):
icecast = "icecast://" ICECAST2_USER ":" ICECAST2_PASS "@localhost:" ICECAST2_PORT "/" mount
stream = (
ffmpeg
.input(source)
.output(
icecast,
audio_bitrate=BITRATE, sample_rate=SAMPLE_RATE, format=FORMAT, acodec=CODEC,
reconnect="1", reconnect_streamed="1", reconnect_at_eof="1", reconnect_delay_max="120",
ice_name=name, ice_genre=source
)
)
return stream
with open('stations.csv', mode='r') as data:
for station in csv.DictReader(data):
stream = run(station['name'], station['mount'], station['url'])
thread = Thread(target=stream.run)
thread.start()
據我了解,我不能單獨重定向每個執行緒的標準輸出,我也不能使用僅由環境變數配置的 ffmpeg 報告。我還有其他選擇嗎?
uj5u.com熱心網友回復:
您需要創建自己的執行緒函式
def stream_runner(stream,id):
# open a stream-specific log file to write to
with open(f'stream_{id}.log','wt') as f:
# block until ffmpeg is done
sp.run(stream.compile(),stderr=f)
for i, station in enumerate(csv.DictReader(data)):
stream = run(station['name'], station['mount'], station['url'])
thread = Thread(target=stream_runner,args=(stream,i))
thread.start()
像這樣的東西應該作業。
uj5u.com熱心網友回復:
ffmpeg-python 并沒有為您提供執行此操作的工具 - 您想控制 subprocess 的引數之一stderr,但 ffmpeg 沒有此引數。
但是,ffmpeg-python 確實具有顯示它會使用的命令列引數的能力。之后,您可以自己呼叫 subprocess 。
您也不需要使用執行緒來執行此操作 - 您可以設定每個 ffmpeg 子行程,而無需等待它完成,并每秒檢查一次。此示例并行啟動兩個 ffmpeg 實體,并通過每秒列印出每個實體的最新輸出行來監視每個實體,并跟蹤它們是否已退出。
我為測驗做了兩個更改:
- 它從字典而不是 CSV 檔案中獲取電臺。
- 它轉碼 MP4 檔案而不是音頻流,因為我沒有 icecast 服務器。如果你想測驗它,它希望在同一目錄中有一個名為“sample.mp4”的檔案。
兩者都應該很容易改回來。
import ffmpeg
import subprocess
import os
import time
stations = [
{'name': 'foo1', 'input': 'sample.mp4', 'output': 'output.mp4'},
{'name': 'foo2', 'input': 'sample.mp4', 'output': 'output2.mp4'},
]
class Transcoder():
def __init__(self, arguments):
self.arguments = arguments
def run(self):
stream = (
ffmpeg
.input(self.arguments['input'])
.output(self.arguments['output'])
)
args = stream.compile(overwrite_output=True)
with open(self.log_name(), 'ab') as logfile:
self.subproc = subprocess.Popen(
args,
stdin=None,
stdout=None,
stderr=logfile,
)
def log_name(self):
return self.arguments['name'] "-ffmpeg.log"
def still_running(self):
return self.subproc.poll() is None
def last_log_line(self):
with open(self.log_name(), 'rb') as f:
try: # catch OSError in case of a one line file
f.seek(-2, os.SEEK_END)
while f.read(1) not in [b'\n', 'b\r']:
f.seek(-2, os.SEEK_CUR)
except OSError:
f.seek(0)
last_line = f.readline().decode()
last_line = last_line.split('\n')[-1]
return last_line
def name(self):
return self.arguments['name']
transcoders = []
for station in stations:
t = Transcoder(station)
t.run()
transcoders.append(t)
while True:
for t in list(transcoders):
if not t.still_running():
print(f"{t.name()} has exited")
transcoders.remove(t)
print(t.name(), repr(t.last_log_line()))
if len(transcoders) == 0:
break
time.sleep(1)
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/504221.html
上一篇:Tokio執行緒管理:從封裝執行緒內部重新啟動子執行緒?
下一篇:Z3py背景關系使用
