Windows – Looping on image2pipe with FFMPEG

ffmpegpythonwindows 7

I have a Python program that generates images at various intervals. I'd like to be able to create a streaming video of each image as it appears. Previously I was using an ffmpeg command like

ffmpg -re -loop 1 -i image.jpg -c:v libx264 -pix_fmt yuv420p out.mp4

I would just have my code overwrite image.jpg whenever it created a new image. However, I'd like to be able to just pipe directly to the ffmpeg command so I don't have to deal with saving the file.

I know I can use something like

ffmpeg -re -y -f image2pipe -vcodec mjpeg -r 24 -i - ...

to take a constant input stream, but I'd like to be able to take one image and loop over it until another one is ready. Is that possible? Just throwing the loop flag into the above doesn't seem to work.

A little more information: I'm running this all on Windows via Python's subprocess command and sending the images in via subprocess.PIPE to stdin. I think my problem has to do with getting the ffmpeg command correct and not with Python, which is why I'm posting it here.

Best Answer

I found the best solution was to actually just overwrite the image locally. I played around a lot with pipes and processes in Python, but nothing worked as well as just running ffmpeg from the command line and overwriting the image. I ended up doing this on Linux, but it should work on Windows.

ffmpeg command:

ffmpeg -re -loop 1 -i out.jpg -re -f lavfi -i aevalsrc=0 -codec:v libx264 -video_size 1280x720 -f flv -strict experimental rtmp://...

ffmpeg streams to an rtmp URL, but it should be easy to change it to save locally. Just change the -f flag to your desired format and the URL to the file name.

Python code:

import cv2
import os
import threading

class ffmpegHelper(threading.Thread):
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.image_queue = queue
        self.timer = 1


    def tick(self):
        threading.Timer(self.timer,self.tick).start()
        temp = None
        if not self.image_queue.empty():
            temp = self.image_queue.get()
        try:
            cv2.imwrite("temp.jpg",temp)
            os.rename("temp.jpg","out.jpg")
        except:
            print "Temp didn't get fully written"
            print "Skipping this frame"


    def run(self):
        self.tick()

The Python code's not the cleanest in the world, but it should work. It writes to "temp.jpg" first so ffmpeg doesn't end up reading from the image when Python's writing it.