2

When I run ffprobe <video>, I get the standard metadata as below:

ffprobe version 4.3.1 Copyright (c) 2007-2020 the FFmpeg developers built with Apple clang version 11.0.3 (clang-1103.0.32.62) configuration: --prefix=/opt/local --enable-swscale --enable-avfilter --enable-avresample --enable-libmp3lame --enable-libvorbis --enable-libopus --enable-librsvg --enable-libtheora --enable-libopenjpeg --enable-libmodplug --enable-libvpx --enable-libsoxr --enable-libspeex --enable-libass --enable-libbluray --enable-lzma --enable-gnutls --enable-fontconfig --enable-libfreetype --enable-libfribidi --disable-libjack --disable-libopencore-amrnb --disable-libopencore-amrwb --disable-libxcb --disable-libxcb-shm --disable-libxcb-xfixes --disable-indev=jack --enable-opencl --disable-outdev=xv --enable-audiotoolbox --enable-videotoolbox --enable-sdl2 --disable-securetransport --mandir=/opt/local/share/man --enable-shared --enable-pthreads --cc=/usr/bin/clang --enable-libdav1d --arch=x86_64 --enable-x86asm --enable-libx265 --enable-gpl --enable-postproc --enable-libx264 --enable-libxvid libavutil 56. 51.100 / 56. 51.100 libavcodec 58. 91.100 / 58. 91.100 libavformat 58. 45.100 / 58. 45.100 libavdevice 58. 10.100 / 58. 10.100 libavfilter 7. 85.100 / 7. 85.100 libavresample 4. 0. 0 / 4. 0. 0 libswscale 5. 7.100 / 5. 7.100 libswresample 3. 7.100 / 3. 7.100 libpostproc 55. 7.100 / 55. 7.100 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '../directConversion/200mbs105_55.mp4': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : Lavf58.45.100 Duration: 00:01:12.43, start: 0.000000, bitrate: 213963 kb/s Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 1080x1920 [SAR 1:1 DAR 9:16], 213828 kb/s, 30 fps, 30 tbr, 15360 tbn, 60 tbc (default) Metadata: handler_name : Core Media Video Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 128 kb/s (default) Metadata: handler_name : Core Media Audio 

I want to get this information from python so I can parse this output and use some of it in my code. However, I can't get this to work.

I have tried the following:

data = subprocess.call(f'ffprobe {video}', shell=True) data = subprocess.check_output(f'ffprobe {vid}', shell=True) data = subprocess.Popen(f'ffprobe {vid}', shell=True) data = subprocess. Popen(f'ffprobe {vid}', stdout=subprocess.PIPE ).communicate()[0] data = run(f'ffprobe {vid}', capture_output=True).stdout 

If I include shell=True, then the proper information prints in the terminal but I get an empty string for data. For commands without shell=True I get file not found error and it breaks. What should I do? I got all of these solutions from SO and they seem to work for others.

6
  • ffprobe is in your shell path, but not in the path of Python context. As an ad hock solution, you can use full path. The default path in Linux is /usr/bin/ffprobe. If it isn't there, use which ffprobe in your shell. Note: for easy parsing, you may ask FFprobe to return the data in JSON format, and convert the string to Python dictionary. Commented Apr 29, 2021 at 13:45
  • When I run which ffprobe I get /opt/local/bin/ffprobe. What should I do with this info? Also, how do I get the JSON as you recommend? Commented Apr 29, 2021 at 13:50
  • Changing my command to f'/opt/local/bin/ffprobe {vid} results in no change Commented Apr 29, 2021 at 13:51
  • Are you using Mac or Linux? I don't think I can help you with the path. For JSON format, use ffprobe -print_format json. Then use dict = json.loads(data). Commented Apr 29, 2021 at 14:11
  • 1
    I think I know the problem: You should use shlex.split: data = run(shlex.split(f'ffprobe {vid} -print_format json'), capture_output=True).stdout Commented Apr 29, 2021 at 14:21

1 Answer 1

3

You may use shlex.split or put the arguments to FFprobe in a list.

In Windows OS, you can use sp.run(f'ffprobe {video}' ...
In Linux and Mac, Python tries to execute the command as file name with spaces.
For example: 'ffprobe vid.mp4' is considered a single executable command (file name with space).

You may use an arguments list:
sp.run(['ffprobe', f'{video}']...

Or use shlex.split for splitting the shell command to a list:
sp.run(shlex.split(f'ffprobe {video}'))...


For simple parsing FFprobe output in Python:

  • Execute ffprobe with -of json argument, and get the output in JSON format.
  • Convert the output string to dictionary using json.loads.

Here is a code sample that reads the output of FFprobe into a dictionary:

import subprocess as sp import shlex import json video = 'vid.mkv' # Execute ffprobe (to show streams), and get the output in JSON format data = sp.run(shlex.split(f'ffprobe -loglevel error -show_streams -of json {video}'), capture_output=True).stdout # Same - using a list of arguments: # data = sp.run(['ffprobe', '-loglevel', 'error', '-show_streams', '-of', 'json', f'{video}'], capture_output=True).stdout # Convert data from JSON string to dictionary d = json.loads(data) print(d) # Print the dictionary for testing 

Notes:

  • I used -show_streams argument as an example.
    In case there is missing (or too much) information, look for the relevant set of arguments.
  • The example assumes that ffprobe is in the execution path.
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.