4

I'm trying to use the python 2.7 python-vlc to parse then get the duration of a music track from a URL. Parsing doesn't work and playing then pausing the media returns -1 for the duration occasionally.

There are two ways I know of to parse media, which has to be done before using media.get_duration(). I can parse it, or I can play it.

No matter what, I cannot parse the media. Using parse_with_options() gives me parsed status MediaParsedStatus.skipped for everything except for parse_with_option(1,0)which gives me parsed status MediaParsedStatus.FIXME_(0L)

        p = vlc.MediaPlayer(songurl)
        media = p.get_media()
        media.parse_with_options(1, 0)
        print media.get_parsed_status()
        print media.get_duration()

The string "songurl" is the actual streaming URL of a song from Youtube or Google Play Music, which works perfectly fine with the MediaPlayer.

I have also tried playing the media for short 0.01 to 0.5 second periods then attempting to get the time, which works MOST OF THE TIME but randomly returns a duration of -1 about 1 in 10 times. Using media.get_duration() again returns the same result.

I would prefer to just parse the song rather than worry about playing it, but I can't figure out any way to parse it. I already submitted a bug report to the python-vlc github since I figure MediaParsedStatus.FIXME_(0L) is some sort of bug.

UPDATE: I GOT IT! This was possibly the biggest pain in all my programming career (which isnt much). Here's the code used to get the time for a URL track:

        instance = vlc.Instance()
        media = instance.media_new(songurl)
        player = instance.media_player_new()
        player.set_media(media)
        #Start the parser
        media.parse_with_options(1,0)
        while True:
            if str(media.get_parsed_status()) == 'MediaParsedStatus.done':
                break #Might be a good idea to add a failsafe in here.
        print media.get_duration()
rxbots
  • 87
  • 1
  • 8
  • As you have noticed, attempting to get the media duration before it has been parsed, results in grief. A simple method is to check the `status` for playing, once it is playing the duration is available. Also be aware that the `duration` can change. Sometimes it can take a while to settle down. So to be accurate, you need to check the duration every now and then or bind the event handler to the event `vlc.EventType.MediaPlayerLengthChanged` - Good luck! – Rolf of Saxony Apr 14 '19 at 19:14

2 Answers2

2

media.parse_with_options is asynchronous. So your code isn't waiting for a response from URL, it's just immediately moving on. As with all asynchronous methods, you need to receive a notification that the data has been received and then you can move on. In this case it looks like it is the MediaParsedChanged event.

https://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__media.html#ga55f5a33e22aa32e17a9bb75decd1497b

Alternatively, you should be able to use the parse() method which is synchronous and will block until the meta data is received. This isn't recommended (and it's deprecated) because it could block indefinitely and lock up. But it is an option depending on what you are using the code for.

https://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__media.html#ga4b71084fb35b3dd8cc6457a4d27baf0c

EDIT:

If you need an example of using the event manager with the python bindings, here is a great example: VLC Python EventManager callback type?

Particularly, look at Rolf's answer as the way he is using it might be a good starting point for you.

import vlc
parseReady = 0

def ParseReceived(event):
    global parseReady
    #set a flag that your data is ready
    parseReady = 1
...
events = player.event_manager()
events.event_attach(vlc.EventType.MediaParsedChanged, ParseReceived)
...
parseReady = 0
media.parse_with_options(1, 0)
while parseReady == 0:
    #TODO: spin something to waste time

#Once the flag is set, your data is ready
print media.get_parsed_status()
print media.get_duration()

There are undoubtedly better ways to do it but that's a basic example. Note, according to the documentation, you can not call vlc methods from within an event callback. Thus the use of a simple flag rather that calling the media methods directly in the callback.

avariant
  • 2,234
  • 5
  • 25
  • 33
  • `parse()` doesn't work whatsoever and gives me the same `MediaParsedStatus.skipped` issue. I cannot for the life of me decipher how the event listener for libvlc works which seems unbelievably overcomplicated just to get the duration of one single media track. – rxbots Apr 05 '19 at 20:43
  • I've added a link and some code on using the event manager. I haven't tried it so it may require some tweaks but the basic idea is there and isn't too hard to implement. – avariant Apr 05 '19 at 23:25
1

libvlc will not parse network resources by default. You need to call parse with options with libvlc_media_parse_network.

mfkl
  • 1,914
  • 1
  • 11
  • 21
  • To clarify, is this done by using `parse_with_option(1,0)` ? I've tried this and I keep getting the error `MediaParsedStatus.FIXME_(0L)` – rxbots Apr 06 '19 at 04:29