title: Getting video properties with Python without calling external software
body: <p>[Update:] Yes, it is possible, now some 20 months later. See Update3 below! [/update]</p>
  
  <p>Is that really impossible? All I could find were variants of calling FFmpeg (or other software). My current solution is shown below, but what I really would like to get for portability is a Python-only solution that doesn't require users to install additional software.  </p>
  
  <p>After all, I can easily play videos using PyQt's Phonon, yet I can't get simply things like dimension or duration of the video?</p>
  
  <p>My solution uses ffmpy (<a href="http://ffmpy.readthedocs.io/en/latest/ffmpy.html" rel="noreferrer">http://ffmpy.readthedocs.io/en/latest/ffmpy.html</a> ) which is a wrapper for FFmpeg and FFprobe (<a href="http://trac.ffmpeg.org/wiki/FFprobeTips" rel="noreferrer">http://trac.ffmpeg.org/wiki/FFprobeTips</a>). Smoother than other offerings, yet it still requires an additional FFmpeg installation.</p>
  
  <pre><code>    import ffmpy, subprocess, json
      ffprobe = ffmpy.FFprobe(global_options="-loglevel quiet -sexagesimal -of json -show_entries stream=width,height,duration -show_entries format=duration -select_streams v:0", inputs={"myvideo.mp4": None})
      print("ffprobe.cmd:", ffprobe.cmd)  # printout the resulting ffprobe shell command
      stdout, stderr = ffprobe.run(stderr=subprocess.PIPE, stdout=subprocess.PIPE)
      # std* is byte sequence, but json in Python 3.5.2 requires str
      ff0string = str(stdout,'utf-8')
  
      ffinfo = json.loads(ff0string)
      print(json.dumps(ffinfo, indent=4)) # pretty print
  
      print("Video Dimensions: {}x{}".format(ffinfo["streams"][0]["width"], ffinfo["streams"][0]["height"]))
      print("Streams Duration:", ffinfo["streams"][0]["duration"])
      print("Format Duration: ", ffinfo["format"]["duration"])
  </code></pre>
  
  <p>Results in output:</p>
  
  <pre><code>    ffprobe.cmd: ffprobe -loglevel quiet -sexagesimal -of json -show_entries stream=width,height,duration -show_entries format=duration -select_streams v:0 -i myvideo.mp4
      {
          "streams": [
              {
                  "duration": "0:00:32.033333",
                  "width": 1920,
                  "height": 1080
              }
          ],
          "programs": [],
          "format": {
              "duration": "0:00:32.064000"
          }
      }
      Video Dimensions: 1920x1080
      Streams Duration: 0:00:32.033333
      Format Duration:  0:00:32.064000
  </code></pre>
  
  <p><strong>UPDATE</strong> after several days of experimentation: The hachoire solution as proposed by Nick below does work, but will give you a lot of headaches, as the hachoire responses are too unpredictable. Not my choice.</p>
  
  <p>With opencv coding couldn't be any easier:</p>
  
  <pre><code>import cv2
  vid = cv2.VideoCapture( picfilename)
  height = vid.get(cv2.CAP_PROP_FRAME_HEIGHT) # always 0 in Linux python3
  width  = vid.get(cv2.CAP_PROP_FRAME_WIDTH)  # always 0 in Linux python3
  print ("opencv: height:{} width:{}".format( height, width))
  </code></pre>
  
  <p>The problem is that it works well on Python2 but not on Py3. Quote: <em>"IMPORTANT NOTE: MacOS and Linux packages do not support video related functionality (not compiled with FFmpeg)"</em> (<a href="https://pypi.python.org/pypi/opencv-python" rel="noreferrer">https://pypi.python.org/pypi/opencv-python</a>).</p>
  
  <p>On top of this it seems that opencv needs the presence of the binary packages of FFmeg at runtime (<a href="https://docs.opencv.org/3.3.1/d0/da7/videoio_overview.html" rel="noreferrer">https://docs.opencv.org/3.3.1/d0/da7/videoio_overview.html</a>).</p>
  
  <p>Well, if I need an installation of FFmpeg anyway, I can stick to my original ffmpy example shown above :-/ </p>
  
  <p>Thanks for the help.</p>
  
  <p><strong>UPDATE2:</strong> master_q (see below) proposed MediaInfo. While this failed to work on my Linux system (see my comments), the alternative of using pymediainfo, a py wrapper to MediaInfo, did work. It is simple to use, but it takes 4 times longer than my initial ffprobe approach to obtain duration, width and height, and still needs external software, i.e. MediaInfo:</p>
  
  <pre><code>from pymediainfo import MediaInfo
  media_info = MediaInfo.parse("myvideofile")
  for track in media_info.tracks:
      if track.track_type == 'Video':
          print("duration (millisec):", track.duration)
          print("width, height:", track.width, track.height)
  </code></pre>
  
  <p><strong>UPDATE3:</strong> OpenCV is finally available for Python3, and is claimed to run on Linux, Win, and Mac! It makes it really easy, and I verfied that external software - in particular ffmpeg - is NOT needed!</p>
  
  <p>First install OpenCV via Pip:</p>
  
  <pre><code>pip install opencv-python
  </code></pre>
  
  <p>Run in Python:</p>
  
  <pre><code>import cv2
  cv2video = cv2.VideoCapture( videofilename)
  height = cv2video.get(cv2.CAP_PROP_FRAME_HEIGHT)
  width  = cv2video.get(cv2.CAP_PROP_FRAME_WIDTH) 
  print ("Video Dimension: height:{} width:{}".format( height, width))
  
  framecount = cv2video.get(cv2.CAP_PROP_FRAME_COUNT ) 
  frames_per_sec = cv2video.get(cv2.CAP_PROP_FPS)
  print("Video duration (sec):", framecount / frames_per_sec)
  
  # equally easy to get this info from images
  cv2image = cv2.imread(imagefilename, flags=cv2.IMREAD_COLOR  )
  height, width, channel  = cv2image.shape
  print ("Image Dimension: height:{} width:{}".format( height, width))
  </code></pre>
  
  <p>I also needed the first frame of a video as an image, and used ffmpeg for this to save the image in the file system. This also is easier with OpenCV:</p>
  
  <pre><code>hasFrames, cv2image = cv2video.read()   # reads 1st frame
  cv2.imwrite("myfilename.png", cv2image) # extension defines image type
  </code></pre>
  
  <p>But even better, as I need the image only in memory for use in the PyQt5 toolkit, I can directly read the cv2-image into an Qt-image:</p>
  
  <pre><code>bytesPerLine = 3 * width
  # my_qt_image = QImage(cv2image, width, height, bytesPerLine, QImage.Format_RGB888) # may give false colors!
  my_qt_image = QImage(cv2image.data, width, height, bytesPerLine, QImage.Format_RGB888).rgbSwapped() # correct colors on my systems
  </code></pre>
  
  <p>As OpenCV is a huge program, I was concerned about timing. Turned out, OpenCV was never behind the alternatives. I takes some 100ms to read a slide, all the rest combined takes never more than 10ms.</p>
  
  <p>I tested this successfully on Ubuntu Mate 16.04, 18.04, and 19.04, and on two different installations of Windows 10 Pro. (Did not have Mac avalable). I am really delighted about OpenCV!</p>
  
  <p>You can see it in action in my SlideSorter program, which allows to sort images and videos, preserve sort order, and present as slideshow. Available here: <a href="https://sourceforge.net/projects/slidesorter/" rel="noreferrer">https://sourceforge.net/projects/slidesorter/</a> </p>