How to use log_set with python binding?

This forum is about all development around libVLC.
User avatar
joba1
New Cone
New Cone
Posts: 6
Joined: 09 Mar 2016 00:42

How to use log_set with python binding?

Postby joba1 » 09 Mar 2016 01:34

Hi,

I want to code a music player that shows guitar chords of the currently playing song. It should run on linux and if possible also on windows.
Since I just started learning python and like the gui coding with tkinter, I searched for a way to play music in python.
Platform independent audio implementations with a reasonable set of codecs seem to be sparse, but finally I found the vlc.py wrapper for libvlc.

Unfortunately I'm not getting very far. The example code tkvlc.py is running fine, but my own code with MediaListPlayer stays quiet.
My MediaListPlayer.play() just returns -1
Probably a stupid beginner mistake. Time to read the log output. But how?

I browsed the web but could not find a single example of log_set being used with libvlc python binding.
So I tried to make some sense out of the code. It seems, the class vlc.Instance defines log_set, but with wrong parameters: In Instance.log_set(self, data, p_instance): self is the instance object, but in the implementation it gets passed as the callback function with libvlc_log_set(self, data, p_instance).
A fix would be this method implementation:

Code: Select all

def log_set(self, data, cb): return libvlc_log_set(cb, data, self)
For now I guess I might just call vlc.libvlc_log_set(cb, data, instance) directly.
But how do I get a valid LogCB to pass cb? Preferably one that somehow maps to the python logging module?
A code snippet showing that would be very welcome :)

Currently I do this

Code: Select all

self.instance = vlc.Instance() cb = vlc.LogCb() vlc.libvlc_log_set(cb, None, self.instance)
and recieve that:
Traceback (most recent call last):
File "C:\Users\joba1\workspace\chordsplay\ChordsPlay\__main__.py", line 107, in main
gui = ChordsPlay.gui.Gui(program_name)
File "C:\Users\joba1\workspace\chordsplay\ChordsPlay\gui.py", line 28, in __init__
self.player = ChordsPlay.play.Play(songlist)
File "C:\Users\joba1\workspace\chordsplay\ChordsPlay\play.py", line 31, in __init__
vlc.libvlc_log_set(cb, None, self.instance)
File "C:\Program Files (x86)\Python35-32\lib\site-packages\vlc.py", line 4097, in libvlc_log_set
return f(cb, data, p_instance)
ctypes.ArgumentError: argument 1: <class 'AttributeError'>: 'LogCb' object has no attribute '_as_parameter_'

panic82
New Cone
New Cone
Posts: 8
Joined: 01 Sep 2016 19:15

Re: How to use log_set with python binding?

Postby panic82 » 04 Sep 2016 14:10

Hi did you ever figure this out? I'm looking for a similar example of intercepting log messages, but I'm having a hard time finding a working example. Thanks

eman123
New Cone
New Cone
Posts: 4
Joined: 22 Aug 2016 08:20

Re: How to use log_set with python binding?

Postby eman123 » 07 Sep 2016 09:03

Hi did you find a solution for this ? i have same problem. I'm passing different streams to vlc using python but i need to read the logs in order to identify if streams are valid or not

menew
New Cone
New Cone
Posts: 2
Joined: 27 Apr 2017 07:14

Re: How to use log_set with python binding?

Postby menew » 27 Apr 2017 07:28

`vlc.LogCb` is only an alias of `ctypes.c_void_p` to make the declaration of
`libvlc_log_set` function's argument types readable. You cannot use it as
concrete function that will be called back.

Instead, use `vlc.CallbackDecorators.LogCb` function decorator to make your
Python function callable from C library, like following:

Code: Select all

import vlc @vlc.CallbackDecorators.LogCb def log_callback(data, level, ctx, fmt, args): # Do something interesting pass instance = vlc.Instance() instance.log_set(log_callback, None)
Callback has been set correctly, but unfortunately, there is another pitfall
here. As you can see in argument names of `log_callback` function above,
"format string" (`fmt`) and its formatting argument (`args`) are passed
separatedly, unformatted. So you will be disappointed if you simply call
`print(fmt)` in callback.

`args` is `va_list` type, that is "variable-length argument list" type used in
libc, therefore you must use libc functions like `vprintf` / `vsprintf` via
ctypes module to build formatted string correctly. Pure Python cannot handle
it.

An important thing to be cared is that internal `va_list` structure may depend
on the versions of libc. It means you must format it with `vprintf` /
`vsprintf` in the same version of libc as libvlc using. It may not be problem
on *nix environments, but may be problem on Windows environment (e.g. On my
laptop, libvlc uses shared MSVCRT.dll as libc, but CPython uses shared
MSVCR90.dll on the other hand).

Pulling it all together:

Code: Select all

import ctypes import sys import vlc # Prepare `vsnprintf` function if sys.platform.startswith('win'): # Note: must use same version of libc as libvlc vsnprintf = ctypes.cdll.msvcrt.vspnrintf else: libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library('c')) vsnprintf = libc.vsnprintf vsnprintf.restype = ctypes.c_int vsnprintf.argtypes = ( ctypes.c_char_p, ctypes.c_size_t, ctypes.c_char_p, ctypes.c_void_p, ) # Your callback here @vlc.CallbackDecorators.LogCb def log_callback(data, level, ctx, fmt, args): # Skip if level is lower than warning if level < vlc.LogLevel.WARNING: return # Format given fmt/args pair BUF_LEN = 1024 outBuf = ctypes.create_string_buffer(BUF_LEN) vsnprintf(outBuf, BUF_LEN, fmt, args) # Print it out, or do something else print('LOG: ' + outBuf.raw) # Set callback to the libvlc instance instance = vlc.Instance() instance.log_set(log_callback, None)
FYI: If you want to simply read debug log output of libvlc on development
time, you can get it easily by passing `--verbose` command line option to
`vlc.Instance` constructor.

Code: Select all

instance = vlc.Instance('--verbose 3')
Or, you can use `libvlc_log_set_file` function, but it may cause problem
similar to `va_list` above; you must pass `FILE` structure pointer of the same
version of libc as libvlc using, therefore you may need to use raw `fopen`
function on some environments.

Code: Select all

instance = vlc.Instance() # May work on some environments that Python uses same libc as libvlc # f = open('out.log', 'w') # instance.log_set_file(vlc.PyFile_AsFile(f)) # Or you should use raw `fopen` of the same version of libc instead fopen = ctypes.cdll.msvcrt.fopen fopen.restype = vlc.FILE_ptr fopen.argtypes = (ctypes.c_char_p, ctypes.c_char_p) f = fopen('out.log', 'w') instance.log_set_file(f)

OlivierAubert
Developer
Developer
Posts: 92
Joined: 08 Mar 2007 15:43

Re: How to use log_set with python binding?

Postby OlivierAubert » 22 Sep 2017 22:52

Very good and precise explanation of the issues. It would be very nice if we could somehow integrate some of your code into the bindings themselves so that it is more intuitive to people. The plugin code is auto-generated from the bindings, but we can override some methods to add a more pythonic behaviour. Feel free to propose a patch to the bindings.

wrybread
Blank Cone
Blank Cone
Posts: 17
Joined: 24 Mar 2007 05:44

Re: How to use log_set with python binding?

Postby wrybread » 31 Oct 2018 17:24

Is anyone able to get this working on Windows? On Windows 7 with Python 2.7 I get the error:

Code: Select all

Traceback (most recent call last): File "D:\Projects\easyptz\EasyPTZ.py", line 340, in <module> vsnprintf = ctypes.cdll.msvcrt.vspnrintf File "C:\Python27\lib\ctypes\__init__.py", line 379, in __getattr__ func = self.__getitem__(name) File "C:\Python27\lib\ctypes\__init__.py", line 384, in __getitem__ func = self._FuncPtr((name_or_ordinal, self)) AttributeError: function 'vspnrintf' not found
I have a feeling it relates to this passage from the answer above, but I don't know how to investigate:
An important thing to be cared is that internal `va_list` structure may depend
on the versions of libc. It means you must format it with `vprintf` /
`vsprintf` in the same version of libc as libvlc using. It may not be problem
on *nix environments, but may be problem on Windows environment (e.g. On my
laptop, libvlc uses shared MSVCRT.dll as libc, but CPython uses shared
MSVCR90.dll on the other hand).

menew
New Cone
New Cone
Posts: 2
Joined: 27 Apr 2017 07:14

Re: How to use log_set with python binding?

Postby menew » 02 Dec 2018 17:28

Code: Select all

Traceback (most recent call last): File "D:\Projects\easyptz\EasyPTZ.py", line 340, in <module> vsnprintf = ctypes.cdll.msvcrt.vspnrintf File "C:\Python27\lib\ctypes\__init__.py", line 379, in __getattr__ func = self.__getitem__(name) File "C:\Python27\lib\ctypes\__init__.py", line 384, in __getitem__ func = self._FuncPtr((name_or_ordinal, self)) AttributeError: function 'vspnrintf' not found
Oh, sorry. There is typo: use `vsnprintf` instead of `vspnrintf`.


Return to “Development around libVLC”

Who is online

Users browsing this forum: No registered users and 6 guests