5

Environment: Docker, Ubuntu 20.04, OpenCV 3.5.4, FFmpeg 4.2.4

Im currently reading the output of a cv2.VideoCapture session using the CV_FFMPEG backend and successfully writing that back out in real time to a file using cv2.VideoWriter. The reason I am doing this is to drawing bounding boxes on the input and saving it to a new output.

The problem is I am doing this in a headless environment (Docker container). And I’d like to view what's being written to cv2.VideoWriter in realtime.

I know there are ways to pass my display through using XQuartz for example so I could use cv2.imshow. But what I really want to do is write those frames to an RTSP Server. So not only my host can "watch" but also other hosts could watch too.

After the video is released I can easily stream the video to my RTSP Server using this command.

ffmpeg -re -stream_loop -1 -i output.mp4 -c copy -f rtsp rtsp://rtsp_server_host:8554/stream

Is there anyway to pipe the frames as they come in to the above command? Can cv2.VideoWriter itself write frames to an RTSP Server?

Any ideas would be much appreciated! Thank you.

evanhutomo
  • 627
  • 1
  • 11
  • 24
chasez0r
  • 544
  • 5
  • 18
  • look into VideoWriter with a gstreamer pipeline string instead of a file path – Christoph Rackwitz Sep 29 '21 at 16:15
  • Thanks for the pointer! I am using this for my RTSP server https://github.com/aler9/rtsp-simple-server and it does provide examples for streaming with Gstreamer. It's documentation, as well as every example I've seen (so far) is always making the assumption the file has been closed. Any links that point to how to use Gstreamer with a file that is open and being written to? – chasez0r Sep 29 '21 at 17:46
  • use multiple VideoWriters. or use ffmpeg (ffmpeg has APIs/libraries). OpenCV is a library for computer vision, not for video encoding. – Christoph Rackwitz Sep 29 '21 at 18:22
  • Thanks! I figured it out below. – chasez0r Sep 29 '21 at 21:10

1 Answers1

8

After much searching I finally figured out how to do this with FFmpeg in a subprocess. Hopefully this helps someone else!

def open_ffmpeg_stream_process(self):
    args = (
        "ffmpeg -re -stream_loop -1 -f rawvideo -pix_fmt "
        "rgb24 -s 1920x1080 -i pipe:0 -pix_fmt yuv420p "
        "-f rtsp rtsp://rtsp_server:8554/stream"
    ).split()
    return subprocess.Popen(args, stdin=subprocess.PIPE)


def capture_loop():
    ffmpeg_process = open_ffmpeg_stream_process()
    capture = cv2.VideoCapture(<video/stream>)    
    while True:
        grabbed, frame = capture.read()
        if not grabbed:
            break
        ffmpeg_process.stdin.write(frame.astype(np.uint8).tobytes())
    capture.release()
    ffmpeg_process.stdin.close()
    ffmpeg_process.wait()
chasez0r
  • 544
  • 5
  • 18
  • 1
    how do you start the recepient rtsp server and how you choose the ip address?..thanks – Lakshay Dulani Oct 04 '22 at 13:44
  • I'm getting this error: Connection to tcp://localhost:8554?timeout=0 failed: Connection refused Could not write header for output file #0 (incorrect codec parameters ?): Connection refused Error initializing output stream 0:0 -- – M.Hossein Rahimi Nov 21 '22 at 21:28