4

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

1 Answer 1

1

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()
Sign up to request clarification or add additional context in comments.

1 Comment

do you know how to make a broadcast using this solution? :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.