libvlc-go
libvlc-go copied to clipboard
Deadlock on player actions after MediaPlayerEndReached
Hi,
I'm trying to make it that instead of the player re-initializing when using loop (and thus causing the player to close and open), I thought to work around this by using the event manager and resetting the media position once it reaches the end of the video.
So I made the following:
eventCallback := func(event vlc.Event, userData interface{}) {
log.Println("Restarting video")
if player.IsPlaying() {
log.Println("Stop")
if err := player.Stop(); err != nil {
log.Fatalf("Unable to stop player: %s", err)
}
}
log.Println("Setting media position")
if err := player.SetMediaTime(0); err != nil {
log.Fatalf("Unable to reset media position: %s", err)
}
log.Println("Play")
if err := player.Play(); err != nil {
log.Fatalf("Unable to start player: %s", err)
}
}
....
eventID, err := manager.Attach(vlc.MediaPlayerEndReached, eventCallback, nil)
However, once I hit SetMediaTime, I hit a deadlock. It just hangs there. Can you give me any pointers on why this is ?
Kind regards
Hi @Heathland. Thank you for your interest in the library.
Can you provide more information regarding the logic of your application? Are you trying to achieve 'gapless' playback? That's not possible in libVLC 3 unfortunately.
The deadlock is caused by the fact that you are calling libVLC
functionality that mutates the state of the player from the event manager thread. That's not a limitation of this library. It's a known issue of libVLC
.
A workaround for that is to wrap your code in a Go routine:
go func() {
// your code here.
}()
That won't solve the issue though, because when the MediaPlayerEndReached
is triggered, the media instance is finished, it cannot be replayed. You can retrieve the media instance from the player and call SetMedia
with it again and then play, but that would cause the player to close and then reopen.
One option that does work, but it's not very configurable, is to pass --input-repeat
when initializing the library.
if err := vlc.Init("--input-repeat=999999", "--quiet"); err != nil {
log.Fatal(err)
}
defer vlc.Release()
But that's quite limiting in many scenarios. Another option, is to use the vlc.MediaPlayerTimeChanged
event and set the media time a bit before it ends.
package main
import (
"log"
vlc "github.com/adrg/libvlc-go/v3"
)
func main() {
// Initialize libVLC. Additional command line arguments can be passed in
// to libVLC by specifying them in the Init function.
if err := vlc.Init("--input-repeat=999999", "--quiet"); err != nil {
log.Fatal(err)
}
defer vlc.Release()
// Create a new player.
player, err := vlc.NewPlayer()
if err != nil {
log.Fatal(err)
}
defer func() {
player.Stop()
player.Release()
}()
// Add a media file from path.
media, err := player.LoadMediaFromPath("sample.mp4")
if err != nil {
log.Fatal(err)
}
defer media.Release()
// Retrieve player event manager.
manager, err := player.EventManager()
if err != nil {
log.Fatal(err)
}
// Register the media end reached event with the event manager.
quit := make(chan struct{})
eventCallback := func(event vlc.Event, userData interface{}) {
mediaLength, _ := player.MediaLength()
mediaTime, _ := player.MediaTime()
if mediaLength > 0 && mediaTime >= mediaLength-500 {
go func() {
if err := player.SetMediaTime(0); err != nil {
log.Fatalf("unable to reset media position: %s", err)
}
}()
}
}
eventID, err := manager.Attach(vlc.MediaPlayerTimeChanged, eventCallback, nil)
if err != nil {
log.Fatal(err)
}
defer manager.Detach(eventID)
// Start playing the media.
err = player.Play()
if err != nil {
log.Fatal(err)
}
<-quit
}
Hi @adrg ,
You hit the nail right on the head. Yeah I'm trying to do exactly as you mention. In the past I've used omxplayer. But due to it not being supported anymore in the latest Raspberry OS version (Buster), and their push to VLC, I thought I'd give VLC a go and then using bindings to boot. However, I noticed that VLC kept restarted the player, causing it to close and reopen for a short moment and not behaving as omxplayer does, which just smoothly loops. Also I noticed it redownloads the media everytime it restarted. I get why, as omxplayer doesn't have a list media feature, and VLC does. But due to that it needs to reinitialize with each asset. So I thought I could work around by just resetting the playback position to the start of the video once it ended.
I already had a feeling the fact that the media had the state Ended that was the cause. I'll give your suggestion a shot. Thank you for the answer and this awesome lib!
I'm glad to help. Let me know how it goes.
Closing this issue as it has been addressed. Please reopen if the provided solution did not work for you.