先說(shuō)下實(shí)現(xiàn)原理休讳,如下圖:
Python使用cv2拉取攝像頭的視頻幀耐齐,壓縮笤成、解碼羡蛾、編碼等處理后將圖片base64編碼后通過(guò)websocket發(fā)送給服務(wù)端漓帅,服務(wù)端將此幀圖片存下來(lái),當(dāng)有客戶端請(qǐng)求圖片數(shù)據(jù)時(shí)服務(wù)端不斷地將圖片幀發(fā)送給請(qǐng)求websocket客戶端痴怨∶Ω桑客戶端不斷的刷新圖片以達(dá)到視頻播放的效果。
可以根據(jù)代碼中quality參數(shù)設(shè)置圖片的質(zhì)量4流暢3高清2標(biāo)清1超清浪藻,本人測(cè)試在1M帶寬的網(wǎng)絡(luò)環(huán)境可以達(dá)到1秒10幀捐迫、延遲低的效果只是畫面效果不好。標(biāo)清則需要大約5M帶寬爱葵,高清大概需要10M帶寬施戴,超清需要20M帶寬。
Python端代碼如下:
#向服務(wù)端發(fā)送數(shù)據(jù)的線程
import cv2
import base64
import websocket
import threading
class SendThread (threading.Thread):
def __init__(self, video_url, ws_server_url, camera_id):
threading.Thread.__init__(self)
#"rtsp://admin:a1234567@192.168.8.11:554/h264/ch1/main/av_stream"
self._video_url = video_url
self._ws = None
self._ws_server_url = ws_server_url
self._capture = None
self._send = True
#視頻播放質(zhì)量4流暢3標(biāo)清2高清1超清
self._quality = 4
self._camera_id = camera_id
def run(self):
websocket.enableTrace(False)
self._ws = websocket.WebSocketApp(self._ws_server_url,
on_message=self.on_message,
on_error=self.on_error,
on_close=self.on_close,
on_open=self.on_open)
self._ws.run_forever()
def send_frame(self):
self._capture = cv2.VideoCapture(self._video_url)
frame_width = int(self._capture.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(self._capture.get(cv2.CAP_PROP_FRAME_HEIGHT))
while self._send:
ret, frame = self._capture.read()
if ret:
# 576,324
r = int(2 + self._quality * 0.5)
frame = cv2.resize(frame,(frame_width // r,frame_height // r))
#圖片質(zhì)量1-100
jpeg_quality = 100 - 10 * self._quality
img_param = [int(cv2.IMWRITE_JPEG_QUALITY), jpeg_quality]
# 轉(zhuǎn)化
ret, frame = cv2.imencode('.jpg', frame, img_param)
if ret:
self._ws.send(base64.b64encode(frame).decode("utf-8"))
def on_message(self, message):
print(message)
def on_error(self, error):
print(error)
global send_thread_pool
del send_thread_pool[self._camera_id]
self._send = False
self._capture.release()
def on_close(self):
print("closed video send!")
global send_thread_pool
del send_thread_pool[self._camera_id]
self._send = False
self._capture.release()
def on_open(self):
print('連接媒體服務(wù)器成功!')
global send_thread_pool
send_thread_pool[self._camera_id] = self
self.send_frame()
def set_quality(self, quality):
self._quality = quality
web頁(yè)面代碼如下:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>視頻播放</title>
<script type="text/javascript">
var wsVideo = new WebSocket("ws://video/read/e064213cf7ba449cbc2904c95fab0);
wsVideo.onmessage = function(evt){
document.getElementById("img1").src = "data:image/jpeg;base64," + evt.data;
}
</script>
</head>
<body>
<div id="sse">
<img id="img1" width="100%" height="100%">
</div>
</body>
</html>