Live Streaming Video Chat without Voice using cv2 Python Module

Govind Bhardwaj
6 min readJun 10, 2021

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 threading
class 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()

def startVideo(self):
try:
threading.Thread(target=self.sendVideo,args=()).start()
threading.Thread(target=self.recvVideo,args=()).start()
except ConnectionResetError:
print("Connection Lose")
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”
  • Visit this Video to get see demo -
  • To get the code go to below GitHub Repo Link -

--

--