Live Streaming Video Chat without Voice using cv2 Python Module
Introduction to Python -
Python is an interpreted high-level general-purpose programming language. Python’s design philosophy emphasizes code readability with its notable use of significant indentation.
Its high-level built in data structures, combined with dynamic typing and dynamic binding, make it very attractive for Rapid Application Development, as well as for use as a scripting .
Introduction to “opencv-python” Python Library-
OpenCV is the huge open-source library for computer vision, machine learning, and image processing and now it plays a major role in real-time operation which is very important in today’s systems.
By using it, one can process images and videos to identify objects, faces, or even the handwriting of a human.
When it integrated with various libraries, such as numpy, python is capable of processing the OpenCV array structure for analysis. To Identify image patterns and its various features we use vector space and perform mathematical operations on these features.
To install "opencv-python" library# pip3 install opencv-python (In Linux) # pip install opencv-python (In Windows)
Now let’s start to make our “Live Stream Video Chat” -
In “Live Stream Video Chat” we will use two terms “initiator” ( Who will initiate Video Chat Request )and “accepter” ( Who will accept or attend Video Chat /Request ).
Follow Python Module we will use — numpy , cv2 ,socket , threading
We created a class “VideoStream” in module also same name as “VideoStream”.
import cv2 import socket from numpy import frombuffer import threadingclass VideoStream(): def__init__(self,socket_name=None,stream_mode="accepter",peering_name=None,cam_url=None,RECVED_MAX_BYTES=65470,title=None,cam_index=0): """ socket_name : It's must be tuble. First element of this variable of this property must be IP and Second Port Number . Use empty string instead of IP is you want to dynamically attach current IP of system . This required property .User have stream_mode : stream_mode will tell that system will work as accepter ( who will accept the Video Chat Request) or initiator ( who will initiate the request for Video Chat) . This property value can be either "accepter" or "initiator" . By Default value of this is "accepter". peering_name : This is required when stream_mode is "initiator" . This will tell to initiator that on which endpoint it will connect. cam_url : This property will used when if Camera is on remote destination then You have to give the URL for that camera . RECVED_MAX_BYTES : recv() method in TCP socket programming only receive limited data at a time according to their buffer size. This will set buffer size for recv() method . By default 65472 title : When cv2.imshow() open a windows then this method take first argument for title of that window cam_index : This property will tell us which camera you want to use (Internal or External) . To use Internal camera this property value must be 0 and to use external camera this property value must be 1 . Internal ---> 0 External ---> 1 This property has by default value 0 """ self.cam_index=cam_index self.title=title self.socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.socket.bind(socket_name) self.RECVED_MAX_BYTES=RECVED_MAX_BYTES # Take Camera Reference self.cap = cv2.VideoCapture(self.cam_index) # Image Dimension self.recv_frame_dim =3 if cam_url != None and isinstance(cam_url,str): self.cap.open(cam_url) if stream_mode == "accepter": self.socket.listen() self.socket,addr=self.socket.accept() self.socket.send(b'done') # Now it will check connection with transfer some data # If connection is good then here image shape also be shared if self.socket.recv(4).decode() != "done": print("Connection Failed") exit() photo=self.cap.read()[1] if len(photo) !=0: shape=photo.shape self.socket.send(bytes("{0} {1}".format(shape[0],shape[1]).encode())) co_ordinates = self.socket.recv(10).decode().split(" ") self.recv_frame_column = int(co_ordinates[0]) self.recv_frame_row = int(co_ordinates[1]) else: print("Camera not connected") elif stream_mode == "initiater": self.socket.connect(peering_name) if self.socket.recv(4).decode() != "done": print("Connection Failed") exit() # Now it will check connection with transfer some data # If connection is good then here image shape also be shared self.socket.send(b'done') co_ordinates = self.socket.recv(10).decode().split(" ") self.recv_frame_column = int(co_ordinates[0]) self.recv_frame_row = int(co_ordinates[1]) photo=self.cap.read()[1] if len(photo) !=0: shape=photo.shape self.socket.send(bytes("{0} {1}".format(shape[0],shape[1]).encode())) else: print("Camera not connected")
def recvVideo(self): while True: frame = b'' try: datapayload=self.socket.recv(self.RECVED_MAX_BYTES).split(b"/") seg = int(datapayload[0].decode()) frame = frame + b"/".join(datapayload[1:]) seg -= 1 while (seg) >= 1: if seg == 1: frame_segment_payload=self.socket.recv((self.recv_frame_column*self.recv_frame_row*self.recv_frame_dim)-len(frame)) else: frame_segment_payload=self.socket.recv(self.RECVED_MAX_BYTES) frame += frame_segment_payload seg -= 1 except ConnectionResetError: print("Connection Lose") exit() cv2.imshow(self.title,frombuffer(frame,dtype='uint8').reshape(self.recv_frame_column,self.recv_frame_row,3)) if cv2.waitKey(10) ==13: break cv2.destroyAllWindows() self.cap.release()
def sendVideo(self): while True: returnCode , photo = self.cap.read() if returnCode and len(photo) != 0: frame = photo.tobytes() # No of segments -> int(len(frame)/self.RECVED_MAX_BYTES)+1 seg = len(frame)/self.RECVED_MAX_BYTES if seg != int(seg): seg = int(seg) + 1 try: self.socket.send(bytes(str(seg).encode())+ b"/" + frame) except ConnectionResetError: print("Connection Lose") exit() else: print("Camera can't read") self.cap.release() exit()
“VideoStream” class have one constructor “__init__” ( Here socket will be created , share some data like both how much size of images will send and check connection from both is proper or not )and three methods “recvVideo” ( It will receive video from other network ), “sendVideo” (It will send video through network) , “startVideo” ( It have two threads so that we can send and receive video in parallel )
__init__() this constructor creating a socket and check the connection with send data “done” and also sharing to other node that it will send shape of array of image
recvVideo() will receive packet in segments because in socket programming service can receive a limited no of bytes at a time according to its buffer size. In this method first segment of packet contain that how much are total no of segments are there for this packet . No of segment and packet data is separated by “/” . This method also display the image using cv2 module.
frombuffer() method is converting bytes into again numpy array. it return 1-d array but __init__() initially have received that what will be shape of received array . Now we can again change this 1-d to its original array
sendVideo() will send network packets . Here we are also appending that the segment of packet because any node can receive a limited no of bytes at a time . We can tell recvVideo() with no of segments that after receiving this much segments means it have received who image data .
startVideo() will create and start two threads for recvVideo() and sendVideo() methods so that server or node can receive and send data parallelly
Here in our case “Person A” is accepter and “Person B” is initiator .
Now run first Accepter “Person_A” Because if Accepter doesn’t have a socket then other can will not be able to connect it . the run Initiator “Person_B”