Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ffmpeg with python subprocess Popen

I'm trying to record webcam video from python using ffmpeg. The following ffmpeg works properly when run from the cmd

ffmpeg -f dshow -rtbufsize 2000M -i video="HP HD Camera":audio="Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)" -y -vcodec libx264 -crf 24 output.mp4 

I have checked the audio and video inputs with

ffmpeg -list_devices true -f dshow -i dummy

Now when I try to call the command using subprocess problem happens. I can just pass the whole command like this

import subprocess, time
recorder = subprocess.Popen('ffmpeg -f dshow -rtbufsize 2000M -i video="HP HD Camera":audio="Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)" -y -vcodec libx264 -crf 24 output.mp4', shell=True)
time.sleep(10)
recorder.terminate()
recorder.kill()

Now, as this is run with shell=True this won't terminate the recording and I have checked different solution, but they won't work either. So, I opted for shell=False. I tried with

recorder = subprocess.Popen(['ffmpeg', '-f', 'dshow', '-rtbufsize', '2000M', '-t', '60', '-i', 'video="HP HD Camera":audio="Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)"', '-y', '-vcodec', 'libx264', '-crf', '24', 'output.mp4'],shell=False)

This throws the error

[dshow @ 0000024f2becd540] Could not find video device with name ["HP HD Camera"] among source devices of type video.
video="HP HD Camera":audio="Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)": I/O error

Then, I tried

recorder = subprocess.Popen(['ffmpeg', '-f', 'dshow', '-rtbufsize', '2000M', '-t', '60', '-i', 'video=HP HD Camera:audio=Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)', '-y', '-vcodec', 'libx264', '-crf', '24', 'output.mp4'],shell=False)

This creates the output, but the video is not playable.
How to fix this?

like image 752
Eular Avatar asked Nov 29 '25 01:11

Eular


1 Answers

We may add double quotes for letting Python subprocess know the string is one argument, and we have to close FFmpeg gracefully.

Adding double quotes:
Replace the following part video="HP HD Camera":audio="Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)" with:
"video=""HP HD Camera"":audio=""Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)"""
Doubling the quotes "" is required because " is between quotes " ... ".

We may also use it without the "": "video=HP HD Camera:audio=Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)".


For getting a playable file, we have to close FFmpeg gracefully.
For simply recording 10 seconds, we may add -t 10 argument.

For closing FFmpeg gracefully programmatically, we may write 'q'.encode("GBK") to stdin pipe of FFmpeg sub-process.
Writing q simulates that q key is pressed by the user (stop recording).

  • Add stdin=subprocess.PIPE argument to subprocess.Popen.

  • After time.sleep(10) add:

     recorder.stdin.write('q'.encode("GBK"))  # Simulate user pressing q key
     recorder.communicate()
    
  • Add recorder.wait() (instead of recorder.terminate() and recorder.kill()).


As good practice we may also add shlex.split(...) for converting the command line to a list of arguments.
In Windows it supposed to work without it, but in Linux it's not.

Code sample:

import subprocess, time, shlex

recorder = subprocess.Popen(shlex.split('ffmpeg -f dshow -rtbufsize 2000M -t 60 -i """video=HP HD Camera:audio=Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)"":""audio=Headset (realme Buds Wireless 2 Neo Hands-Free AG Audio)"""'
                                        ' -y -vcodec libx264 -crf 24 output.mp4'), stdin=subprocess.PIPE, shell=False)

time.sleep(10)

recorder.stdin.write('q'.encode("GBK"))  # Simulate user pressing q key
recorder.communicate()
recorder.wait()
like image 79
Rotem Avatar answered Dec 02 '25 05:12

Rotem