Losing key frame when using opencv and gstreamer to send my webcam video on a web server

Viewed 274

I'm trying to stream my webcam video to show it on an HTML page. To do that, I'm using Opencv to capture the video from my webcam. Then, I'm using GStreamer to send the video from the sender app to my webserver which I've built with Flask. For my Gstreamer pipeline, I'm using the codec h264 and UDP (IP: 127.0.0.1, port: 5000). For now, I'm using UDP locally to test my server. Later the camera won't necessarily be my webcam so I will send the video through the network. That is why I'm not directly getting the webcam video in the server application.

Problems are the following :

  • I'm losing key frames so the image shown on the webserver is very noisy
  • I have a big latency (more than 2 sec)

Does anyone know how to improve that? Is it a better way than using GStreamer?

Here is my code :

you have to put the file sender.py and server.py in a directory. In this same directory create another directory named templates. In this last directory put the file home.html

sender.py

import cv2


cap = cv2.VideoCapture(0)  # open the camera

if cap.isOpened():
    # get vcap property
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))  # float
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))  # float
else:
    width = 1280
    height = 720

fourcc = cv2.VideoWriter_fourcc(*'H264')
out = cv2.VideoWriter('appsrc ! videoconvert ! x264enc tune=zerolatency noise-reduction=0 speed-preset=ultrafast ! rtph264pay config-interval=1 pt=96 ! udpsink host=127.0.0.1 port=5000', fourcc, cv2.CAP_PROP_FPS, (1280, 720), True) #ouput GStreamer pipeline

if not out.isOpened():
    print('VideoWriter not opened')
    exit(0)

while cap.isOpened():
    ret, frame = cap.read()

    if ret:

        # Write to pipeline
        frame = cv2.resize(frame, (1280, 720))
        out.write(frame)

        cv2.imshow("test", frame)

        if cv2.waitKey(1)&0xFF == ord('q'):
            break

cap.release()
out.release()

server.py

import cv2
from flask import Flask, render_template, Response
import os

ip = "127.0.0.1"
port = 5001

cap = cv2.VideoCapture(
            'udpsrc port=5000 caps = "application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)H264, payload=(int)96" ! rtph264depay ! decodebin ! videoconvert ! appsink',
            cv2.CAP_GSTREAMER)

if not cap.isOpened():
    print('VideoCapture not opened')
    raise ValueError("Cam with Gstreamer pipeline not opened")


def generate():

    while True:
        ret, frame = cap.read()

        if not ret:
            print('empty frame')
            break

        frame = cv2.flip(frame, 1)

        (flag, frame) = cv2.imencode(".png", frame)

        yield b'--frame\r\n' b'Content-Type: image/png\r\n\r\n' + bytearray(frame) + b'\r\n'


def create_app(ip, port, test_config=None):
    # create and configure the app

    app = Flask(__name__, instance_relative_config=True)  # creation of the app
    app.config.from_mapping(
        SECRET_KEY='dev',
        DATABASDE=os.path.join(app.instance_path, 'flaskr.sqlite')
    )

    if test_config is None:
        app.config.from_pyfile('config.py', silent=True)
    else:
        app.config.from_mapping(test_config)

    try:
        os.makedirs(app.instance_path)  # create instance directory because flask doesn't create it on its own
    except OSError:
        pass

    @app.route('/')
    def init_page():
        return render_template('home.html', ip=ip, port=port)

    @app.route('/video_feed')
    def video_feed():
        return Response(generate(), mimetype="multipart/x-mixed-replace; boundary=frame")

    return app


if __name__ == "__main__":
    app = create_app(ip, port)
    app.run(host=ip, port=port, debug=True, threaded=True, use_reloader=False)

home.html

<html>
  <head>
    <title>Front Cam</title>
  </head>
  <body>
    <h1>This is Front cam</h1> <br />
    <img src="{{ url_for('video_feed') }}">
  </body>
</html>

Thanks!

0 Answers
Related