Skip to content

Instantly share code, notes, and snippets.

@n3wtron
Last active July 8, 2024 17:49
Show Gist options
  • Save n3wtron/4624820 to your computer and use it in GitHub Desktop.
Save n3wtron/4624820 to your computer and use it in GitHub Desktop.
Simple Python Motion Jpeg (mjpeg server) from webcam. Using: OpenCV,BaseHTTPServer
#!/usr/bin/python
'''
Author: Igor Maculan - [email protected]
A Simple mjpg stream http server
'''
import cv2
import Image
import threading
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
from SocketServer import ThreadingMixIn
import StringIO
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 = StringIO.StringIO()
jpg.save(tmpFile,'JPEG')
self.wfile.write("--jpgboundary")
self.send_header('Content-type','image/jpeg')
self.send_header('Content-length',str(tmpFile.len))
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>')
self.wfile.write('<img src="http://127.0.0.1:8080/cam.mjpg"/>')
self.wfile.write('</body></html>')
return
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
"""Handle requests in a separate thread."""
def main():
global capture
capture = cv2.VideoCapture(0)
capture.set(cv2.cv.CV_CAP_PROP_FRAME_WIDTH, 320);
capture.set(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT, 240);
capture.set(cv2.cv.CV_CAP_PROP_SATURATION,0.2);
global img
try:
server = ThreadedHTTPServer(('localhost', 8080), CamHandler)
print "server started"
server.serve_forever()
except KeyboardInterrupt:
capture.release()
server.socket.close()
if __name__ == '__main__':
main()
@muka
Copy link

muka commented Oct 22, 2019

This one works

import cv2
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn

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

                    img_str = cv2.imencode('.jpg', img)[1].tostring()

                    self.send_header('Content-type', 'image/jpeg')
                    self.send_header('Content-length', len(img_str))
                    self.end_headers()

                    self.wfile.write(img_str)
                    self.wfile.write(b"\r\n--jpgboundary\r\n")

                except KeyboardInterrupt:
                    self.wfile.write(b"\r\n--jpgboundary--\r\n")
                    break
                except BrokenPipeError:
                    continue
            return

        if self.path.endswith('.html'):
            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            self.wfile.write(b'<html><head></head><body>')
            self.wfile.write(b'<img src="http://127.0.0.1:8081/cam.mjpg"/>')
            self.wfile.write(b'</body></html>')
            return


class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """Handle requests in a separate thread."""


def main():

    global capture
    capture = cv2.VideoCapture(0)
    capture.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
    capture.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)

    global img
    try:
        server = ThreadedHTTPServer(('localhost', 8081), CamHandler)
        print("server started at http://127.0.0.1:8081/cam.html")
        server.serve_forever()
    except KeyboardInterrupt:
        capture.release()
        server.socket.close()

if __name__ == '__main__':
    main()

@foilandwater
Copy link

Nice man!! exactly I was looking for on web. Saved my time 👍 )
I am doing this for rtsp stream.
And this way RTSP gets embedded in a web page.
Thanks

Hi,

Please can you tell me how you did it with an RTSP IP camera onto a web page? I've been researching for weeks to get this done!!

@wennycooper
Copy link

Great work, Igor!

Wolfgang, the program uses pipes (http://www.python-course.eu/pipes.php) to communicate the output to the server. When you disconnect from the port, it breaks the existing pipe, and when you reconnect, it breaks the previous pipe and starts a new one.

If you were running the script locally and the opencv output was displayed in a window, you could use the 'Keyboard Interrupt' to break the loop without any errors. That doesn't work in the browser because you've already used a pipe to get there.

tl;dr : that error is nothing to worry about, you'll pretty much see it every time you disconnect or reconnect.

Hi saif-data, Do you have any idea how to remove those broken pipe error messages? Try/Exception not work..

@ashwin2401
Copy link

import cv2
import numpy as np
import time
from PIL import Image
from io import BytesIO
import threading
from multiprocessing import Process
import config_ip_vid
try:
from http.server import BaseHTTPRequestHandler,HTTPServer
from socketserver import ThreadingMixIn
except ImportError:
from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
from SocketServer import ThreadingMixIn

debug = False
gracefulexit=False
TFrame = None
videoserver = None

port = config_ip_vid.port_number

vid = config_ip_vid.vid_number

for i,j in zip(port,vid):

print("all file and ports******",i,j)

#print('port number -------',port)
#print('video number -------',vid)

#importing all the ports and video from config file
port_8081 = config_ip_vid.port_number1
vid1 = str(config_ip_vid.vid_number1)
print("@@@@@$$$$$$$",str(config_ip_vid.vid_number1))
port_8082 = config_ip_vid.port_number2
vid2 = config_ip_vid.vid_number2

port_8083 = config_ip_vid.port_number3
vid3 = config_ip_vid.vid_number3

port_8084 = config_ip_vid.port_number4
vid4 = config_ip_vid.vid_number4

port_8085 = config_ip_vid.port_number5
vid5 = config_ip_vid.vid_number5

class CamHandler(BaseHTTPRequestHandler):

def do_GET(self):
    global gracefulexit
    if self.path.endswith('.mjpg'):
        self.send_response(200)
        self.send_header('Content-Type','multipart/x-mixed-replace; boundary=--jpgboundary')
        self.send_header('Cache-Control', 'no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0')
        self.end_headers()
        dummy=np.zeros((100,100,3), np.uint8)
        if debug:
            print("vidserver: got new connection")
        while True:
            if gracefulexit:
                break
            try:
                img=TFrame
                if img is None:
                    if debug:
                        print("vidserver: sending dummy")
                    img = dummy

                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(len(tmpFile.getvalue())))
                self.end_headers()
                jpg.save(self.wfile,'JPEG')
                time.sleep(0.05)
            except KeyboardInterrupt:
                print("vidserver: got interrupt")
                break
            except Exception as e:
                print("vidserver error:",e)
                break
        print("Exiting cam thread")
        return
    elif 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:8087/cam.mjpg"/>'.encode())
        self.wfile.write('</body></html>'.encode())
        return

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
daemon_threads=True
pass
"""Handle requests in a separate thread."""

def startVideoServer(video_transmit_ip,video_transmit_port):
print("starting video server on %s" % video_transmit_ip)
global gracefulexit

    try:
        videoserver = ThreadedHTTPServer((video_transmit_ip, video_transmit_port), CamHandler)
        # videoserver.anprObj=self
        videoserver.serve_forever()
    except KeyboardInterrupt:
        pass
    print("Exiting videoserver thread")
    gracefulexit=True
    videoserver.shutdown()

    # cap = cv2.VideoCapture(vid)
    # print("############$$$$$$$$$$$$$$$$$ Cap in process",cap)
    # if (cap.isOpened() == False):
    #     print("Error opening video stream or file")
    #
    # while (cap.isOpened()):
    #     ret, TFrame = cap.read()
    #     print("Tframe---=======",TFrame)
    #     if ret != True: break
    # cap.release()
    # if videoserver is not None:
    #     print("Shutting down video server")
    #     videoserver.shutdown()
    #     videoserver.server_close()
    #     videoserver.socket.close()
    # cv2.destroyAllWindows()

print("port 1%%%%%%",port[0])

print("port 2%%%%%%",port[1])

print("video 1%%%%%%",vid[0])

print("video 2%%%%%%",vid[1])

#for i,j in zip(port,vid):

video_transmit_ip = "localhost"
video_transmit_port = int(port_8081)#int(i)
video_transmit_port2 = int(port_8082)
video_transmit_port3 = int(port_8083)
video_transmit_port4 = int(port_8084)
video_transmit_port5 = int(port_8085)
#print("==========",i)
#print("==========",j)
vthread=threading.Thread(target=startVideoServer,args=(video_transmit_ip,video_transmit_port))
vthread.start()

vthread2=threading.Thread(target=startVideoServer,args=(video_transmit_ip,video_transmit_port2))
vthread2.start()

cap = cv2.VideoCapture(vid1)
cap2 = cv2.VideoCapture(vid2)
#print("############$$$$$$$$$$$$$$$$$ Cap in process",cap)
if (cap.isOpened() == False):
print("Error opening video stream or file")
if (cap2.isOpened() == False):
print("Error opening video stream or file")

while (cap.isOpened()|cap2.isOpened()):
ret, TFrame = cap.read()
ret1, img1 = cap2.read()
#print("Tframe---=======",TFrame)
if ret != True: break
cap.release()
cap2.release()
if videoserver is not None:
print("Shutting down video server")
videoserver.shutdown()
videoserver.server_close()
videoserver.socket.close()
cv2.destroyAllWindows()

**I want add multiple video input source to the web but it only displays one of the starting can any of you guys can help me through it i want to play multiple videos the above code is attached for the reference
**

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment