0

I am trying to pipe output from FFmpeg in Python. I am reading images from a video grabber card and I am successful in reading this to an output file from the command line using dshow. I am trying to grab the images from the card to my OpenCv code to be able to further play with the data. Unfortunately, when I pipe out the images, I just get a display of the video as shown in the link:

link: s000.tinyupload.com/?file_id=15940665795196022618.

The code I used is as shown below:

import cv2
import subprocess as sp
import numpy
import sys
import os
old_stdout=sys.stdout
log_file=open("message.log","w")
sys.stdout=log_file

FFMPEG_BIN = "C:/ffmpeg/bin/ffmpeg.exe"
command = [ FFMPEG_BIN, '-y',
            '-f', 'dshow', '-rtbufsize', '100M',
            '-i', 'video=Datapath VisionAV Video 01' ,
             '-video_size', '640x480',
              '-pix_fmt', 'bgr24', '-r','25',  
          '-f', 'image2pipe', '-' ]    
pipe = sp.Popen(command, stdout = sp.PIPE, bufsize=10**8)

while True:
    # Capture frame-by-frame
    raw_image = pipe.stdout.read(640*480*3)
      # transform the byte read into a numpy array
    image =  numpy.frombuffer(raw_image, dtype='uint8')
    print(image)
    image = image.reshape((480,640,3))          
    if image is not None:
        cv2.imshow('Video', image)

    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
    pipe.stdout.flush()
sys.stdout=old_stdout
log_file.close()
cv2.destroyAllWindows()

Please do provide me some pointers to fix this issue. Help is greatly appreciated.

asendjasni
  • 963
  • 1
  • 16
  • 36
user10890282
  • 41
  • 1
  • 2
  • 10
  • [Piping input AND output of ffmpeg in python](https://stackoverflow.com/questions/43997109/piping-input-and-output-of-ffmpeg-in-python) – Muhammad Furqan Mar 05 '19 at 11:02
  • @Muhammad Furqan adding -f image2pipe in the end before '-' in the ffmpeg command does not seem to give me the video still. Do you have any other suggestions? – user10890282 Mar 05 '19 at 12:40
  • Try to modify the comand as follow `[ FFMPEG_BIN, '-y', '-f', 'dshow', '-rtbufsize', '100M', '-i', 'video=Datapath VisionAV Video 01' ,'-f', 'image2pipe', '-video_size', '640x480', '-pix_fmt', 'bgr24', '-r','25', '-' ]` – asendjasni Mar 05 '19 at 16:56

4 Answers4

1

After you call the sp.Popen you have communicate with it.You can use the following code:

try:    
    pipe = sp.Popen(command, stdout=sp.PIPE, stderr=sp.STDOUT, universal_newlines=True)`

    ffmpeg_output, _ = pipe.communicate()

except  sp.CalledProcessError as err:
     print("FFmpeg stdout output on error:\n" + err.output)

Finally, you can print the output to make sure the above commands worked:

print(ffmpeg_output)

The above statement is going to display the output returned by the communication with the process.

asendjasni
  • 963
  • 1
  • 16
  • 36
  • I tried this by adding these lines before the opencv read. But i get nothing printed on the command line. This program aims to get a continous stream from the video grabber card. I do not know if this is the reason if nothing seems to get printed on the command line.. Any ideas? – user10890282 Mar 05 '19 at 14:25
  • No, I edited my answer. I suggest you test the commands in a script apart so you make sure it's working. – asendjasni Mar 05 '19 at 14:54
  • this is what I got : <_io.TextIOWrapper name=3 encoding='cp1252'> @SenDjasni – user10890282 Mar 05 '19 at 14:57
  • My Bad, try the update, I test it on my terminal and it worked. – asendjasni Mar 05 '19 at 15:03
  • @user10890282 Also, put those command in a `try: except: subprocess.CalledProcessError` since the `subprocess` calls could generate exceptions. – asendjasni Mar 05 '19 at 15:15
  • all the three lines are to be put inside the try: except: subprocess.CalledProcessError ? @SenDjasni – user10890282 Mar 05 '19 at 15:23
  • [For further reading](https://docs.python.org/3/library/subprocess.html#subprocess.CalledProcessError) – asendjasni Mar 05 '19 at 15:26
  • No the updated command did not work. the program just kept running.. i added the try: except: sp.CalledProcessError for the first two lines, but then its shows that except: sp.CalledProcessError is invalid syntax. – user10890282 Mar 05 '19 at 15:29
  • I've added the `try and except` block. – asendjasni Mar 05 '19 at 15:35
  • I tried the updated code. I do not get any output on the command line or any error either. I need to force quit the program to stop it. @SenDjasni – user10890282 Mar 05 '19 at 15:48
  • I suggest you get rid of anything but the subprocess call of `ffmpeg`, this way you make sure that the `ffmpeg call does return the desired output. – asendjasni Mar 05 '19 at 15:51
  • I have only used the ffmpeg part of the code and pipe check code which you suggested. I had commented the opencv read part out when I was trying your suggestion.Isnt that what you mean in your last comment?? @SenDjasni – user10890282 Mar 05 '19 at 15:52
  • Yes exactly. I've created [a file on github](https://github.com/sendjasni/ffmpeg_subprocess/blob/master/test.py). Try to run it. Now any output should be related to FFmpeg command only. – asendjasni Mar 05 '19 at 16:03
  • this is what I did but it does not give me any output on the command line and I see the keyboard interrupt is in the pipe.communicate() line. Maybe its because I am streaming live video from an endoscope camera and not reading from a video file as such?? @SenDjasni – user10890282 Mar 05 '19 at 16:14
  • I'm not quite familiar with `ffmpeg` streaming. I found this [guide](https://trac.ffmpeg.org/wiki/StreamingGuide), it could be of use to you. BTW, when you try a simple `ffmpeg` command, what do you get as output? – asendjasni Mar 05 '19 at 16:21
  • I am able to write out a video file using ffmpeg commands from the command line. My problem is when I am trying to pipe out the ffmpeg output from the video grabber card. I am unable to identify if my problem is with the way I use the pipe or if its simply that we cannot pipe out images from the video grabber. I am not too familiar with piping but just trying to figure it out slowly. @SenDjasni – user10890282 Mar 05 '19 at 16:26
  • Did you take a look at the [FFmpeg pipe doc](https://ffmpeg.org/ffmpeg-protocols.html#pipe). – asendjasni Mar 05 '19 at 16:29
  • I forgot to mention that I work with Windows and python. I did see this way of working with pipes as well. were you just trying to highlight how the pipes are addressed in Unix? @SenDjasni – user10890282 Mar 05 '19 at 16:39
  • What about these two links : [First](https://gist.github.com/hiwonjoon/035a1ead72a767add4b87afe03d0dd7b), [second](http://zulko.github.io/blog/2013/09/27/read-and-write-video-frames-in-python-using-ffmpeg/). – asendjasni Mar 05 '19 at 16:47
  • I have seen these two links and was trying out things based on that, but I am not strong with troubleshooting and so not sure why I am not able to display the same as that I manage just using ffmpeg command with -f dshow option in commandline. @SenDjasni – user10890282 Mar 05 '19 at 17:13
0

I struggled longer with the console application FFmpeg, and finally gave up. It's easier with this extension:

pip install ffmpeg-python

Karl Kroening has published here a very good integration of FFmpeg into Python. With these examples a solution should be possible: https://github.com/kkroening/ffmpeg-python

Thomas Ertl
  • 96
  • 1
  • 4
0

This works for me

import subprocess as sp
import json
import os
import numpy
import PIL
from imutils.video import FPS
import cv2 


def video_frames_ffmpeg():
    width = 640
    height = 360
    iterator = 0
    cmd = ['ffmpeg', '-loglevel', 'quiet',
           '-f', 'dshow',
           '-i', 'video=HD USB Camera',
           #'-vf','scale=%d:%d,smartblur'%(width,height),
           '-preset' ,'ultrafast', '-tune', 'zerolatency',
           '-f', 'rawvideo',
           '-pix_fmt','bgr24',
           '-']
    p = sp.Popen(cmd, stdout=sp.PIPE)

    while True:
        arr = numpy.frombuffer(p.stdout.read(width*height*3), dtype=numpy.uint8)
        iterator += 1 
        if len(arr) == 0:
            p.wait()
            print("awaiting")
            #return
        if iterator >= 1000:
            break

        frame = arr.reshape((height, width,3))
        cv2.putText(frame, "frame{}".format(iterator), (75, 70),
                cv2.cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255,255,255), 2)
        im = Image.fromarray(frame)
        im.save("ffmpeg_test/test%d.jpeg" % iterator)

        yield arr


from PIL import Image
from imutils.video import FPS
for i, frame in enumerate(video_frames_ffmpeg()):
    if i == 0:
        fps = FPS().start()
    else: fps.update()
fps.stop()
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))
cv2.destroyAllWindows()
HAL 9000
  • 23
  • 4
  • while using "gray" instead of "bgr24" i get more fps – HAL 9000 Oct 07 '21 at 12:35
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 07 '21 at 14:04
0

Try:

command = [ FFMPEG_BIN,
            '-rtbufsize', '100M',
            '-i', '/dev/video0' , #change to here to your camera device
            '-video_size', '640x480',
            '-pix_fmt', 'bgr24',# '-r','25',
            '-f', 'image2pipe', #'-'
            '-vcodec', 'rawvideo', '-an', '-'
            ]

I don't know how '-vcodec', 'rawvideo', '-an', '-' this helps, and without it my code doesn't work.

Garid
  • 105
  • 1
  • 3