我有一个AXIS IP摄像机,我可以用http
和rtsp
协议检查它。
http://ca.me.ra.ip/axis-cgi/mjpg/video.cgi?resolution=1024x768&dummy=1520
rtsp://ca.me.ra.ip:554/axis-media/media.amp?videocodec=h264&resolution=640x480
我尝试做的是获取流,在我的服务器中缓冲它,然后广播它,这样通过一个连接到相机,我就可以预览它给多个用户。
我用这段代码计算出来:
#!/usr/bin/python
'''
Author: Igor Maculan - n3wtron@gmail.com
A Simple mjpg stream http server
'''
import cv2
from PIL import Image
import threading
from http.server import BaseHTTPRequestHandler,HTTPServer
from socketserver import ThreadingMixIn
from io import StringIO,BytesIO
import time
capture=None
class CamHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path.endswith('.mjpg'):
self.send_response(200)
self.send_header('Content-type','multipart/x-mixed-replace; boundary=--jpgboundary')
self.end_headers()
while True:
try:
rc,img = capture.read()
if not rc:
continue
imgRGB=cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
jpg = Image.fromarray(imgRGB)
tmpFile = BytesIO()
jpg.save(tmpFile,'JPEG')
self.wfile.write("--jpgboundary".encode())
self.send_header('Content-type','image/jpeg')
self.send_header('Content-length',str(tmpFile.getbuffer().nbytes))
self.end_headers()
jpg.save(self.wfile,'JPEG')
time.sleep(0.05)
except KeyboardInterrupt:
break
return
if self.path.endswith('.html'):
self.send_response(200)
self.send_header('Content-type','text/html')
self.end_headers()
self.wfile.write('<html><head></head><body>'.encode())
self.wfile.write('<img src="http://127.0.0.1:8080/cam.mjpg"/>'.encode())
self.wfile.write('</body></html>'.encode())
return
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
"""Handle requests in a separate thread."""
def main():
global capture
capture = cv2.VideoCapture("rtsp://ca.me.ra.ip:554/axis-media/media.amp?videocodec=h264&resolution=640x480")
capture.set(cv2.CAP_PROP_FRAME_WIDTH, 320);
capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 240);
capture.set(cv2.CAP_PROP_SATURATION,0.2);
global img
try:
server = ThreadedHTTPServer(('0.0.0.0', 8080), CamHandler)
print( "server started")
server.serve_forever()
except KeyboardInterrupt:
capture.release()
server.socket.close()
if __name__ == '__main__':
main()
然后我可以在浏览器中使用此地址检查本地机器中的摄像头:
http://ca.me.ra.ip:8080/cam.mjpg
问题是,如果我在两个浏览器中打开它,服务器会崩溃并出现以下错误:
Assertfctx->async_lock在libavcodec/pthread_frame.c:155失败
链接到pthread_frame.c
152 static void async_unlock(FrameThreadContext *fctx)
153 {
154 pthread_mutex_lock(&fctx->async_mutex);
155 av_assert0(fctx->async_lock); <-- This is the line which throws error
156 fctx->async_lock = 0;
157 pthread_cond_broadcast(&fctx->async_cond);
158 pthread_mutex_unlock(&fctx->async_mutex);
159 }
如果我在本地机器上将摄像头地址更改为capture = cv2.VideoCapture(0)
来广播我的笔记本电脑摄像头,无论我运行多少个浏览器,一切都正常。
有没有一种方法可以解决这个问题,而不改变相机地址如上所示?
1条答案
按热度按时间qij5mzcb1#
我认为这个问题源于两个不同的'do_GET()'在争夺相机的帧数据。
一个解决方案是将相机捕获代码从CamHandler移回main或其自己的线程中,同时将服务器代码移到其自己的线程中。
将相机帧馈送到collections.deque中,您可以使用partial将链接传递到HTTPRequestHandler,并允许任何连接的设备使用deque的第一个元素。
这是从这里的信息整理出来的:https://stackoverflow.com/a/46224191和https://stackoverflow.com/a/52046062
下面是我为此所做的松散代码。