Python結(jié)合ffmpeg 實(shí)現(xiàn)單線程和多線程推流
一、引言
在本文中,我們將詳細(xì)介紹如何使用 Python 進(jìn)行視頻的推流操作。我們將通過兩個(gè)不同的實(shí)現(xiàn)方式,即單線程推流和多線程推流,來展示如何利用 cv2(OpenCV)和 subprocess 等庫將視頻幀推送到指定的 RTMP 地址。這兩種方式都涉及到從攝像頭讀取視頻幀,以及使用 ffmpeg 命令行工具將視頻幀進(jìn)行編碼和推流的過程。
二、單線程推流
以下是單線程推流的代碼:
import cv2 as cv
import subprocess as sp
def push_stream():
# 視頻讀取對(duì)象
cap = cv.VideoCapture(0)
fps = int(cap.get(cv.CAP_PROP_FPS))
w = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
h = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
ret, frame = cap.read()
# 推流地址
rtmpUrl = "rtmp://192.168.3.33:1935/live/"
# 推流參數(shù)
command = ['ffmpeg',
'-y',
'-f', 'rawvideo',
'-vcodec','rawvideo',
'-pix_fmt', 'bgr24',
'-s', "{}x{}".format(w, h),
'-r', str(fps),
'-i', '-',
'-c:v', 'libx264',
'-pix_fmt', 'yuv420p',
'-preset', 'ultrafast',
'-f', 'flv',
rtmpUrl]
# 創(chuàng)建、管理子進(jìn)程
pipe = sp.Popen(command, stdin=sp.PIPE, bufsize=10 ** 8)
# 循環(huán)讀取
while cap.isOpened():
# 讀取一幀
ret, frame = cap.read()
if frame is None:
print('read frame err!')
continue
# 顯示一幀
cv.imshow("frame", frame)
# 按鍵退出
if cv.waitKey(1) & 0xFF == ord('q'):
break
# 讀取尺寸、推流
# img=cv.resize(frame,size)
pipe.stdin.write(frame)
# 關(guān)閉窗口
cv.destroyAllWindows()
# 停止讀取
cap.release()
在這個(gè)單線程的實(shí)現(xiàn)中,我們執(zhí)行以下步驟:
初始化視頻讀取對(duì)象:
- 使用
cv2.VideoCapture(0)來打開默認(rèn)的攝像頭設(shè)備。 - 獲取攝像頭的幀率
fps、寬度w和高度h等參數(shù)。
設(shè)置推流地址和參數(shù):
- 定義
rtmpUrl作為推流的目標(biāo)地址。 - 構(gòu)造
ffmpeg的命令列表command,該列表包含了一系列的參數(shù),如-y表示覆蓋輸出文件、-f rawvideo表示輸入格式為原始視頻等。 - 使用
sp.Popen創(chuàng)建一個(gè)子進(jìn)程,將ffmpeg命令作為子進(jìn)程運(yùn)行,并且將其輸入管道stdin連接到我們的程序。
循環(huán)讀取和推流:
- 在一個(gè)
while循環(huán)中,不斷讀取攝像頭的幀。 - 若讀取失敗,打印錯(cuò)誤信息并繼續(xù)。
- 使用
cv2.imshow顯示當(dāng)前幀,同時(shí)監(jiān)聽q鍵,按下q鍵時(shí)退出程序。 - 將讀取到的幀通過管道發(fā)送給
ffmpeg進(jìn)行推流。
三、多線程推流
以下是多線程推流的代碼:
import queue
import threading
import cv2 as cv
import subprocess as sp
class Live(object):
def __init__(self):
self.frame_queue = queue.Queue()
self.command = ""
# 自行設(shè)置
self.rtmpUrl = ""
self.camera_path = ""
def read_frame(self):
print("開啟推流")
cap = cv.VideoCapture(self.camera_path)
# Get video information
fps = int(cap.get(cv.CAP_PROP_FPS))
width = int(cap.get(cv.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv.CAP_PROP_FRAME_HEIGHT))
# ffmpeg command
self.command = ['ffmpeg',
'-y',
'-f', 'rawvideo',
'-vcodec','rawvideo',
'-pix_fmt', 'bgr24',
'-s', "{}x{}".format(width, height),
'-r', str(fps),
'-i', '-',
'-c:v', 'libx264',
'-pix_fmt', 'yuv420p',
'-preset', 'ultrafast',
'-f', 'flv',
self.rtmpUrl]
# read webcamera
while(cap.isOpened()):
ret, frame = cap.read()
if not ret:
print("Opening camera is failed")
break
# put frame into queue
self.frame_queue.put(frame)
def push_frame(self):
# 防止多線程時(shí) command 未被設(shè)置
while True:
if len(self.command) > 0:
# 管道配置
p = sp.Popen(self.command, stdin=sp.PIPE)
break
while True:
if self.frame_queue.empty()!= True:
frame = self.frame_queue.get()
# process frame
# 你處理圖片的代碼
# write to pipe
p.stdin.write(frame.tostring())
def run(self):
threads = [
threading.Thread(target=Live.read_frame, args=(self,)),
threading.Thread(target=Live.push_frame, args=(self,))
]
[thread.setDaemon(True) for thread in threads]
[thread.start() for thread in threads]
在這個(gè)多線程的實(shí)現(xiàn)中,我們使用了 threading 和 queue 庫:
類的初始化:
- 創(chuàng)建一個(gè)
Live類,在__init__方法中初始化幀隊(duì)列frame_queue、command、rtmpUrl和camera_path等變量。
讀取幀的線程方法:
read_frame方法中,使用cv2.VideoCapture(self.camera_path)打開攝像頭。- 獲取攝像頭的參數(shù),并構(gòu)造
ffmpeg命令。 - 不斷從攝像頭讀取幀,并將幀放入隊(duì)列
frame_queue中。
推流的線程方法:
push_frame方法中,等待command被設(shè)置,然后使用sp.Popen啟動(dòng)ffmpeg子進(jìn)程。- 從幀隊(duì)列中取出幀,并將其寫入
ffmpeg的輸入管道進(jìn)行推流。
啟動(dòng)線程:
run方法創(chuàng)建并啟動(dòng)兩個(gè)線程,一個(gè)用于讀取幀,一個(gè)用于推流,并且將它們?cè)O(shè)置為守護(hù)線程。
四、代碼解釋和注意事項(xiàng)
單線程推流:
- 這種方式相對(duì)簡(jiǎn)單,適合初學(xué)者理解。但由于是單線程操作,在處理復(fù)雜任務(wù)時(shí)可能會(huì)導(dǎo)致性能瓶頸,特別是在同時(shí)進(jìn)行視頻顯示、讀取和推流的情況下,可能會(huì)出現(xiàn)卡頓現(xiàn)象。
多線程推流:
- 利用多線程可以將不同的任務(wù)分配給不同的線程,提高性能。
frame_queue是一個(gè)線程安全的隊(duì)列,用于在兩個(gè)線程之間傳遞幀數(shù)據(jù),避免了數(shù)據(jù)競(jìng)爭(zhēng)問題。setDaemon(True)使得線程在主線程結(jié)束時(shí)自動(dòng)終止,防止程序無法正常退出。
五、總結(jié)
通過上述代碼和解釋,我們可以看到如何使用 Python 進(jìn)行單線程和多線程的視頻推流操作。單線程代碼簡(jiǎn)單明了,但性能可能受限;多線程代碼可以更好地處理高負(fù)載,但也需要注意線程安全和資源管理等問題。在實(shí)際應(yīng)用中,我們可以根據(jù)具體的需求和硬件性能來選擇合適的推流方式。同時(shí),我們可以進(jìn)一步優(yōu)化代碼,例如添加異常處理、優(yōu)化幀處理邏輯等,以提高程序的穩(wěn)定性和性能。
到此這篇關(guān)于Python結(jié)合ffmpeg 實(shí)現(xiàn)單線程和多線程推流的文章就介紹到這了,更多相關(guān)Python ffmpeg 單線程和多線程推流內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python字典如何獲取最大和最小value對(duì)應(yīng)的key
這篇文章主要介紹了python字典如何獲取最大和最小value對(duì)應(yīng)的key問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
python 執(zhí)行文件時(shí)額外參數(shù)獲取的實(shí)例
今天小編就為大家分享一篇python 執(zhí)行文件時(shí)額外參數(shù)獲取的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-12-12
Python實(shí)現(xiàn)csv文件(點(diǎn)表和線表)轉(zhuǎn)換為shapefile文件的方法
這篇文章主要介紹了Python實(shí)現(xiàn)csv文件(點(diǎn)表和線表)轉(zhuǎn)換為shapefile文件的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-10-10
使用Python Flask實(shí)現(xiàn)簡(jiǎn)易文件上傳功能
在平時(shí)工作中,文件上傳是一項(xiàng)常見的需求,例如將應(yīng)用異常時(shí)通過腳本生成的dump文件收集起來進(jìn)行分析,但實(shí)現(xiàn)起來卻可能相當(dāng)復(fù)雜,在本文中,我們將探討如何使用Flask實(shí)現(xiàn)文件上傳功能,編寫Dockerfile將應(yīng)用程序通過docker部署,需要的朋友可以參考下2024-05-05
Pandas庫之DataFrame使用的學(xué)習(xí)筆記
這篇文章主要介紹了Pandas庫之DataFrame使用的學(xué)習(xí)筆記,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
Python利用keras接口實(shí)現(xiàn)深度神經(jīng)網(wǎng)絡(luò)回歸
這篇文章主要為大家詳細(xì)介紹了基于Python語言中TensorFlow的Keras接口,實(shí)現(xiàn)深度神經(jīng)網(wǎng)絡(luò)回歸的方法。文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-02-02
給Django Admin添加驗(yàn)證碼和多次登錄嘗試限制的實(shí)現(xiàn)
這篇文章主要介紹了給Django Admin添加驗(yàn)證碼和多次登錄嘗試限制的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
通過Python實(shí)現(xiàn)電腦定時(shí)關(guān)機(jī)的兩種方法
這篇文章主要介紹了分別利用PyQT5和Tkinter實(shí)現(xiàn)電腦的定時(shí)關(guān)機(jī)小程序,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Python有一定的幫助,快跟隨小編一起學(xué)習(xí)一下吧2021-12-12
Numpy數(shù)組的廣播機(jī)制的實(shí)現(xiàn)
這篇文章主要介紹了Numpy數(shù)組的廣播機(jī)制的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Python實(shí)現(xiàn)快速提取Word表格并轉(zhuǎn)Markdown
這篇文章主要為大家詳細(xì)介紹了一套Python零基礎(chǔ)可操作的代碼方案,幫助測(cè)試工程師3分鐘內(nèi)完成表格提取與轉(zhuǎn)換,直接對(duì)接自動(dòng)化測(cè)試或大模型,需要的小伙伴可以參考下2025-04-04

