Christoph Meyer
Christoph Meyer

Reputation: 93

Stream OpenCV frames to http using ffmpeg

I have a small Python OpenCV project and would like to stream my processed frames to HTTP using ffmpeg.

For this I used the following sources: Pipe and OpenCV to FFmpeg with audio streaming RTMP in Python and https://github.com/kkroening/ffmpeg-python/blob/master/examples/README.md#stream-from-a-local-video-to-http-server

To make things more readable I used the ffmpeg-python library but as far as I understand, it doesn't matter if I open a pipe using subprocess or use the library.

The problem that I have is, that I always get a broken pipe or "Connection refused" when I open the stream with ffplay.

import ffmpeg
import cv2

video_format = "flv"
server_url = "http://localhost:8080"

cap = cv2.VideoCapture(1)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))


process = (
    ffmpeg
    .input('pipe:', format='rawvideo',codec="rawvideo", pix_fmt='bgr24', s='{}x{}'.format(width, height))
    .output(
        server_url,
        #codec = "copy", # use same codecs of the original video
        listen=1, # enables HTTP server
        codec="libx264",
        pix_fmt="yuv420p",
        preset="ultrafast",
        f=video_format)
    .overwrite_output()
    .run()
)

while True:
    ret, frame = cap.read()
    if not ret:
        break
    print("Sending frame")
    process.stdin.write(frame.tobytes())

I also tried to stream using only ffmpeg and FaceTime and that works as i expected.

My operation system is MacOS 12.3

Maybe someone knows how to fix this.

Thanks for your help

Chris

Upvotes: 4

Views: 6965

Answers (1)

Christoph Meyer
Christoph Meyer

Reputation: 93

Ok i fixed it by running the process async. The only problem left is to close the pipe securly when the client closes the connection.

import ffmpeg
import cv2
import subprocess

video_format = "flv"
server_url = "http://localhost:8080"




def start_streaming(width, height,fps):
    process = (
        ffmpeg
        .input('pipe:', format='rawvideo',codec="rawvideo", pix_fmt='bgr24', s='{}x{}'.format(width, height))
        .output(
            server_url + '/stream',
            #codec = "copy", # use same codecs of the original video
            listen=1, # enables HTTP server
            pix_fmt="yuv420p",
            preset="ultrafast",
            f=video_format
        )
        .overwrite_output()
        .run_async(pipe_stdin=True)
    )
    return process

def init_cap():
    cap = cv2.VideoCapture(1)
    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
    return cap, width, height

def run():
    cap, width, height = init_cap()
    fps = cap.get(cv2.CAP_PROP_FPS)
    streaming_process = start_streaming(width, height,fps)
    while True:
        ret, frame = cap.read()
        if ret:
            streaming_process.stdin.write(frame.tobytes())
        else:
            break
    streaming_process.stdin.close()
    streaming_process.wait()
    cap.release()

if __name__ == "__main__":
    run()

Upvotes: 1

Related Questions