pythonpython-3.xvlclibvlcpython-vlc

Why is VLC's .py modue returning 'NoneType' in 'media_player_new'?


I've been running around in circles for a few weeks, and can't get past an infuriating problem... firstly; I'm running 64-bit Win10, with 64-bit Powershell invoking python 3.9 (also 64-bit), which is an app with a Tk GUI, and uses python-vlc. It's been running fine for weeks on a laptop, and I'm now trying to get it work on a PC with the same setup (Win10, 64-bit VLC, 64-bit Python).

The error can be reproduced in a few simple lines right in the Python shell:

PS C:\Users\Vexen\OneDrive> python
Python 3.9.2 (tags/v3.9.2:1a79785, Feb 19 2021, 13:44:55) [MSC v.1928 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import vlc
>>> p = vlc.MediaPlayer("C\:\\Users\\Vexen\\OneDrive\\test.mp3")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\Vexen\AppData\Local\Programs\Python\Python39\lib\site-packages\vlc.py", line 3327, in __new__
    o = instance.media_player_new()
AttributeError: 'NoneType' object has no attribute 'media_player_new'
>>>

Or, using a slightly different method with an explicit .Instance():

>>> import vlc
>>> i=vlc.Instance()
>>> p=i.MediaPlayer()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'MediaPlayer'

And to test what i comes out as on the machine where it doesn't work:

>>> type(i)
<class 'NoneType'>

On the laptop where it works, it says <class 'vlc.Instance'>.

Here's things I've looked at and tried (more detail on each, below):

  1. The correct code required to instantiate a Media Player
  2. Using vlc.Instance('--verbose 3')
  3. vlc.py inbuilt GUI/demo causes the same error
  4. Checking that VLC can open .mp3 files
  5. Reinstalls and 64-bit checks
  6. VLC DLLs locations and the %PATH% environment variable
  7. Checking vlc.py
  8. vlc.py internal issue: Instance.new() call to _CFunctions returns None

(1) Code to create the player

The docs say that .MediaPlayer automatically creates the Instance if it's not done manually. Also this is stated here: AttributeError: 'NoneType' object has no attribute 'media_player_new' and .

No matter which way I do it (direct in Python, or held open in a gui by setting frmMain.vlc to vlc.MediaPlayer(), I get the same results, so I'm only showcasing the simpler method here.

(2) i = vlc.Instance('--verbose 3')

Python VLC Script error: AttributeError: 'NoneType' object has no attribute 'media_player_new' says about using i = vlc.Instance('--verbose 3') to see possible error messages: Mine outputs "C:\Windows\system32" and no errors.

On the laptop where it works fine, it outputs a screenfull of technical details.

(3) vlc.py inbuilt GUI/demo causes the same error

When looking in vlc.py I see that it's got an inbuilt simple GUI. When I run it, the file itself outputs the same error:

PS C:\Users\Vexen\OneDrive> python C:\Users\Vexen\AppData\Local\Programs\Python\Python39\Lib\site-packages\vlc.py C:\Users\Vexen\OneDrive\test.mp3
AttributeError: 'NoneType' object has no attribute 'media_new' (C:\Users\Vexen\AppData\Local\Programs\Python\Python39\Lib\site-packages\vlc.py 3.0.11115 vs LibVLC b'3.0.12 Vetinari')

This makes me think that it's something inherent to the VLC install or backend DLLs.

(4) Checking that VLC can open .mp3 files

The following makes VLC full app open and play the file correctly:

PS C:\Users\Vexen\OneDrive> C:\Users\Vexen\OneDrive\test.mp3

Also, intentionally providing a wrong filepath to .MediaPlayer() produces the same error, therefore, it's hitting the NoneType error before it gets as far as parsing the filepath parameter.

(5) Reinstalls and 64-bit checks

Many similar questions focus on mismatches between 32-bit and 64-bit installs. E.g. PyInstaller with Python-VLC: No Attribute "media_player_new" Error and https://superuser.com/questions/1281731/how-to-install-64-bit-vlc-library-for-64-bit-python-3-on-windows . I've uninstalled VLC and Python, rebooted, reinstalled, rebooted, and double-checked I've got 64-bit versions of it all installed.

I uninstalled it from both machines, and using advanced install options, done a custom install on both using the exact same settings (not including Python docs, include Tcl, include Python launcher, install for all users).

Checking Python is 64-bit on both machines:

>>> import platform
>>> platform.architecture()[0]
'64bit'

Getting a fresh vlc.py file:

pip3 install python-vlc --force-reinstall

Checking vlc version, on both machines the details match precisely:

PS C:\Users\Vexen\OneDrive> python -m vlc -v
vlc.py: 3.0.11115 (Sat Jul 25 15:07:40 2020 3.0.11)
LibVLC version: 3.0.12 Vetinari (0x3000c00)
LibVLC compiler: gcc version 6.4.0 (GCC)
Plugin path: C:\WINDOWS\system32
Python: 3.9.2 (64bit) Windows 10

And when running the VLC full app, the 'About' screen also states "3.0.12 Vetinari", on both machines.

32-bit and 64-bit mismatchines have different errors (File Not Found, %1 not compatible, etc) to the ones I've got, so, that's not the problem.

Other general install issues questions, e.g., Python vlc install problems and Attribute error when importing VLC module in python , cover some of the same things I've already done.

(6) VLC DLLs locations and the %PATH% environment variable

Python vlc install problems and some other issues have to do with %PATH% and Python not knowing where to look for vlc DLLs, however, that's not the problem in my case.

Microsoft says that Sytem32 is a default location where Windows will search for DLLs: https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order .

I've stepped through vlc.py, and in "find_lib()", I can see it picks up the correct location of libvlc.dll in /system32/. I deleted the 2x DLL files (the other is libvlccore.dll) and replaced them with newer copies from the newer install of VLC. Made no difference, but, it means that I don't need to worry about the %PATH% environment variable, because it finds the DLLs easily and automatically in /system32/.

Also, the dll version above listed by python -m vlc -v correctly found it in /system32/.

(7) Checking vlc.py

I've copied the file from the laptop (where Python can invoke VLC and play .mp3 files fine), to the desktop (where it causes an error), but with the same results. The file version looks exactly the same.

Verifying that I know exactly which vly.py is being used is used; it's in the Stacktrace of the error, and:

>>> vlc.__file__

returns the expected filepath on both machines. Copying it to the local dir doesn't change anything (except the occur occurs in the file in the new location, as you'd expect).

I also downloaded the very latest version of vlc.py from https://git.videolan.org/?p=vlc/bindings/python.git;a=blob;f=generated/3.0/vlc.py;h=fdb603002425e082b1d6b8ac08ab8322248d3ac7;hb=HEAD .

This file produces the same error on the same line of code (albeit a few line numbers different):

  File "C:\Users\Vexen\OneDrive\Music\Pyggy\vlc.py", line 3200, in __new__
    o = instance.media_player_new()
AttributeError: 'NoneType' object has no attribute 'media_player_new'

(8) vlc.py internal issue: Instance.new() call to _CFunctions returns None

It runs find_lib() which correctly sets dll location to system32. The Instance class is initialized (I guess) by Instance.new() , which calls libvlc_new() which returns [b'vlc'], which seems good (it's not None). But it then passes this to _Cfunctions (via f()), which returns None. This is returned as the Instance() instance, and is the source of the problem.

I added some print() statements to vlc.py (when testing, I tend to put the "Line xxxx" in the print statement, to help me remove the prints() later!):

On the PC where it doesn't work:

Line 4685, lib_vlc_new() is sending the following to f(): 1 [b'vlc']
Line 4688 will return the results of f(argc, argv): None
Line 1883, Instance.__new__() is returning the following: None

On the laptop where it does work:

Line 4685, lib_vlc_new() is sending the following to f():  1 [b'vlc']
Line 4688 will return the results of f(argc, argv):  <vlc.Instance object at 0x000001DCD37BA370>
Line 1883, Instance.__new__() is returning the following:  <vlc.Instance object at 0x000001DCD37BA400>

f is the subfunction that calls _Cfunctions.


Solution

  • Whilst talking with the developer community over here, the issue fixed itself. https://github.com/oaubert/python-vlc/issues/170

    Our closing comments included our best guess: A Windows internal cache somewhere. I deleted the DLLs from system32 in preparation for doing yet another reinstall. I tested the program, and it picked up the DLL from "C:\Program Files\VideoLAN\VLC\libvlc.dll" rather than the /system32/ directory. I strongly suspect that within Windows somewhere, the .dll was cached by something like the preload process or some other obscure bit of Windows. There's no user-facing way to clear some of Windows internal caches. The cache became invalid at some point (3 weeks seems an arbitrary (and rather long) cache period, but Windows is infamously opaque). After that, it genuinely loaded a new version from a new install. Perhaps until then, all my attempts were failing due to a preload cache. That's only a guess.

    Correct answer: Just keep trying, even after uninstalling previous versions, manually remove the libvlc.dll and libvclcore.dll , keep restarting, keep checking version numbers. Eventually. it'll start working.