caprica / vlcj

Java framework for the vlc media player
http://www.capricasoftware.co.uk/projects/vlcj
1.13k stars 259 forks source link

what is a media-player-events thread?? #1188

Closed HeeJoon-Kim closed 1 year ago

HeeJoon-Kim commented 1 year ago

Hello!

I have a question about something strange while running vlcj in SpringBoot..

MediaServerInstance [MediaServerInstance.java:103] - http-nio-8181-exec-1 channel_000163 - Media Changed!!  <-- first changed event.
....
MediaServerInstance [MediaServerInstance.java:103] - media-player-events channel_000163 - Media Changed!!  <-- next
....
MediaServerInstance [MediaServerInstance.java:103] - media-player-events channel_000163 - Media Changed!!  <-- next

First event run on "http-nio-8181-exec-1" thread, but next event run on "media-player-events"... And the "media-player-events" thread keeps "running" without interruption. Also, when an event occurs, the "media-player-events" thread is incremented by one.

image

vlcj version is 4.8.2 and heare is a code..

@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
public class MediaServerInstance extends MediaPlayerEventAdapter {
    // list player
    private final MediaListPlayer listPlayer;
    // media player of list player
    private final MediaPlayer player;

    private final MediaList mediaList;
    private final PlayerInfo info = new PlayerInfo();

    public MediaServerInstance(MediaListPlayer listPlayer, MediaPlayer mediaPlayer, MediaList mediaList, MediaServerPropertyChangeService propertyChangeService) {
        // media list
        this.mediaList = mediaList;
        // media player
        this.player = mediaPlayer;
        this.player.events().addMediaPlayerEventListener(this);
        // list player
        this.listPlayer = listPlayer;
        // set media player to list player
        this.listPlayer.mediaPlayer().setMediaPlayer(this.player);
    }

    @Override
    public void mediaChanged(MediaPlayer mediaPlayer, MediaRef media) {
        log.info("{} {} - Media Changed!!", Thread.currentThread().getName(), channelInfo.getChannelId());
        mediaPlayer.submit(() -> {
            List<String> playLists = listPlayer.list().media().mrls();
            Media m = media.duplicateMedia();

            // now play index
            info.setIndex(playLists.indexOf(m.info().mrl()));
            info.setMusicUrl(m.info().mrl());
            m.release();

            log.debug("{} {} - Play index: {}, url: {}", Thread.currentThread().getName(), channelInfo.getChannelId(), info.getIndex(), info.getMusicUrl());

            // record play info
            propertyChangeService.changeMusic(_this);
        });
    }
}

My question is.... How to handle events without the "media-player-events" thread being spawned? Thanks..!!

caprica commented 1 year ago

This comes up from time to time.

Some related discussion in:

Essentially, the threads are due to vlcj's use of JNA, and it is how JNA handles callback events (among other things I suppose) from native VLC code back into Java code.

This is why it is more apparent when you are using lots of events.

The "media-player-events" thread is the name vlcj tells JNA to use for these threads.

The last time I looked at this, I did a LOT of profiling and such, and the results are summarised in one or other of those related issues.

IIRC the basics of it is that just because you see so many Thread instances, it does not actually mean new threads are continually being created since JNA does some cleverness behind the scenes.

It has been a while since I last looked at this, but if someone can point to a specific problem with vlcj not using JNA correctly, I will take another look.

caprica commented 1 year ago

I suppose a follow-up is, despite the seemingly increasing instance counts, are you actually seeing real memory leaks after the GC has run?

HeeJoon-Kim commented 1 year ago

Thanks for quick answer!!

I'm not sure about memory leaks.. I will watch a few days and report it.~!!

caprica commented 1 year ago

Just a note for the future, this problem (if it is a problem) will eventually go away with JDK 21 (or maybe later) when the FFM API is finalised since JNA will no longer be used.

caprica commented 1 year ago

A quick test with vlcj-5.0.0 (currently in development)...

I can't recall any significant differences around vlcj-4.8.x and vlcj-5.x.

This test plays new media every 5 seconds.

No event listener: image

Event listener added for media changed events: image

Looks to be working normally, the absolute number of threads is stable.

caprica commented 1 year ago

Using 4.8.2 and the same test, it was stable but with one seemingly "extra" media-player-events thread from time-to-time:

image

But it was stable, it was not continually increasing.

caprica commented 1 year ago

btw, if you are going to duplicate the media ref, I think you should do it OUTSIDE of the submit call. The media ref param is only valid for the duration of the method call, and submit will run later in a different thread, potentially after the callback method has already returned.

I also think your call to get the list from the player is potentially racy since you are putting it into a separate thread that will run some time later.

In fact, you should only use submit() if you are going to do something that interacts with the native media player, I am not sure you really need to use it given the code I can see above.

caprica commented 1 year ago

Closing due to lack of follow-up, if you have more details to add this can be re-opened.