caprica / vlcj

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

Invalid Memory Access #1062

Closed PulseBeat02 closed 3 years ago

PulseBeat02 commented 3 years ago

Hello, while using VLCJ in my library, I noticed I encountered an issue called "Invalid memory access". The full stacktrace is like so:

Caused by: java.lang.Error: Invalid memory access
    at com.github.pulsebeat02.vlcj.binding.LibVlc.libvlc_media_player_set_media(Native Method) ~[?:?]
    at com.github.pulsebeat02.vlcj.player.base.MediaApi.applyMedia(MediaApi.java:424) ~[?:?]
    at com.github.pulsebeat02.vlcj.player.base.MediaApi.changeMedia(MediaApi.java:405) ~[?:?]
    at com.github.pulsebeat02.vlcj.player.base.MediaApi.prepare(MediaApi.java:85) ~[?:?]
    at com.github.pulsebeat02.vlcj.player.base.MediaApi.play(MediaApi.java:96) ~[?:?]
    at com.github.pulsebeat02.minecraftmedialibrary.video.player.VLCJIntegratedPlayer.start(VLCJIntegratedPlayer.java:144) ~[?:?]
    at com.github.pulsebeat02.deluxemediaplugin.command.VideoCommand.startVideo(VideoCommand.java:282) ~[?:?]
    at com.mojang.brigadier.CommandDispatcher.execute(CommandDispatcher.java:262) ~[patched_1.16.5.jar:git-Paper-553]
    at com.github.pulsebeat02.deluxemediaplugin.command.CommandHandler.onCommand(CommandHandler.java:62) ~[?:?]
    at com.github.pulsebeat02.deluxemediaplugin.command.BaseCommand.execute(BaseCommand.java:59) ~[?:?]
    at org.bukkit.command.SimpleCommandMap.dispatch(SimpleCommandMap.java:159) ~[patched_1.16.5.jar:git-Paper-553]

After some Googling, I saw another issue report say that the reason due to this is because that something is null. After debugging using Intellij, indeed, the MediaAPI had a null media.

debug

Now that I have found the issue, I wonder how would I instantiate such a media object? The exception is thrown when this line (yes it is Minecraft, don't judge (: ) is executed (with the play method). How would I prevent the media object from being null?

I have verified that I have loaded the VLC binaries by adding them to the native search path. After all, this error wouldn't be thrown if the binaries weren't loaded into the classpath. I was suspecting that there may be something fishy going on in the vlc binaries I had, or I forgot to use some Java code to instantiate it.

caprica commented 3 years ago

Helps if you say what version of vlcj you're using, so I can match up the line numbers.

caprica commented 3 years ago

Nevermind, I can see what's going wrong.

It is failing when it tries to create the native media instance via "new path" or "new location". Which of those method it calls depends on whether it's a local file or a network URL.

Anyway, what would really help here is to see what MRL you are passing to play(). That MRL can not be opened.

Now, vlcj should handle this a bit better by not crashing the JVM, and I will make a small change to improve that, but you need to investigate why the MRL you are playing is seemingly invalid in some way.

Post a representative MRL here if you like.

caprica commented 3 years ago

I jumped the gun a bit here. vlcj already has a lot of null protection around this.

I do now need to which version of vlcj you're using.

PulseBeat02 commented 3 years ago

According to my pom.xml, I am using VLCJ 4.6.0. Should I update to 4.7.1?

Also, I have noticed that my VLCJ bindings are only 4.1.0 (which are quite old). I am only using the bindings to set the plugin variable and declare a new instance as shown here (basically the same as what NativeDiscovery does). I should probably update that to 4.5.0 as well.

caprica commented 3 years ago

Presumably you mean vlcj-natives, no, what you have is correct.

caprica commented 3 years ago

You need to please show me an example of the MRL you are passing to play().

PulseBeat02 commented 3 years ago

In terms of MRL, I usually pass in just an absolute path to the video file (for example: "C://Videos//myvideo.mp4").

caprica commented 3 years ago

There is something weird going on, because I can not see in the code how that can be null - I suspect if you use your debugger and look at the right place, not the media instance in your screenshot, it will tell a different story.

Anyway, the actual problem... you are using Java naming conventions on a native Windows platform. For Java apps that is of course OK, but you need to realise your filename is being passed to a Windows native library, and on Windows the forward slashes are not valid for filenames. So, change your forward slashes to backslashes (you likely have to escape them so use double back-slashes), and it should work.

caprica commented 3 years ago

I thought I had documented this gotcha somewhere, perhaps it needs to be more prominent.

PulseBeat02 commented 3 years ago

Hm. Thank you for reminding me of that, but I'm not sure if that is what is causing the issue. In my video player, I pass a File object into it as shown here. The super method is what contains the String MRL (which in this case it is File#getAbsolutePath). I thought that FIle#getAbsoluteMethod should solve this issue (as that is being used as the mrl)

Either way, I would need to debug more around the mrl. I will see if I could update you with more information.

One last question, however. Could this issue be related to VLC binaries? I am using the latest (3.0.12) VLC binaries as in right now for Windows (and running it on Windows). They were the exact ones copied from my VLC folder. Could that be an issue?

caprica commented 3 years ago

Did you try replacing the Java convention forward-slashes with the native convention back-slashes?

caprica commented 3 years ago

It would be very useful if you could put your breakpoint as shown in this screenshot:

image

I suspect that it is NOT in fact null in vlcj code, and that the native library is crashing because of the forward slashes.

PulseBeat02 commented 3 years ago

It would be very useful if you could put your breakpoint as shown in this screenshot:

image

I suspect that it is NOT in fact null in vlcj code, and that the native library is crashing because of the forward slashes.

Thank you. I will try that out tonight.

PulseBeat02 commented 3 years ago

After some debugging, I found that the path I used was indeed correct: C:\Users\Brandon Li\Desktop\server\plugins\DeluxeMediaPlugin\mml\video.mp4 I don't think it's a path issue. I am now going to set the breakpoint in the screenshot you sent and see what happens.

PulseBeat02 commented 3 years ago

Yikes, it looks like Intellij debugger won't properly work for decompiled code (from the vlcj library). The ide won't step into the internal code properly. I will try my best and see what I can do.

caprica commented 3 years ago

Well, add the vlcj sources to your project, that should be possible. In my experience IntelliJ is quite good at debugging with decompiled classes, but since vlcj is open source, just add the source to your project.

I would also make 100% sure the space character in your filename is not causing a problem - this is unlikely, but it's another thing to eliminate.

PulseBeat02 commented 3 years ago

It appears to just be crashing on the exact line you mentioned in the breakpoint. According to the debugger, the mediaPlayerInstance and mediaInstance are defined within that method. When I step into that code (which is a native method), it just throws the exception there. The native method in LibVLC is called "libvlc_media_player_set_media", and it's likely probably some issue within the VLC binaries I have.

Could it be because my options are null? The path should be okay but I will test.

caprica commented 3 years ago

Your original stacktrace, and the screenshot I posted showing you showing the line to breakpoint - that is the only relevant place to check for this supposed null value, which was the premise of your original post. You will see the line numbers in your stacktrace match up with the code in the screenshot I posted.

IMO, nothing in the vlcj classes can be null here, but inspecting the variables at the breakpoint I suggested will show it to be so or not.

libvlc_media_player_set_media uses a native opaque handle created from your "c:\..." MRL, and that is what is passed to LibVLC.

It is extremely unlikely for there to be any problem specifically with this native method tbh.

PulseBeat02 commented 3 years ago

After some inspection, I found that none of the Api classes (inputApi, overlayApi, etc) in the mediaPlayer variable are null. Like so:

debugger

I have verified that the path isn't causing the issue because when I drag the video into my C drive and enter in C:\video.mp4, the same error persists.

There is likely something not on VLCJ side or VLC's side, but I'm not sure what could be causing it. Should I close the issue?

caprica commented 3 years ago

Those API classes being not null is a complete irrelevance, I'm not sure why you keep avoiding the specific point I made with my screenshot - the mediaInstance variable, or its contents, is the only thing that could possibly be null (but even then I'm pretty sure it can't be).

And each time you post, I'm sorry, it raises more questions than answers - you now say in your latest post that you enter "c:\video.mp4", but you really need "c:\\video.mp4". Which did you actually do?

caprica commented 3 years ago

Can VLC itself play your file?

PulseBeat02 commented 3 years ago

I'm sorry. I just didn't quite understand what you were trying to say, and I kept mistyping the paths. To be more specific, the paths are correct, I just keep typing them wrongly in Github (not copying and pasting but typing by hand).

About the mediaInstance variable, it seems to not be null. According to my debugger. This kind of makes me stuck.

For your second part of the question, yes, VLC can play my file. I dragged my mp4 file into VLC Media Player and it managed to load and successfully play the video with no issues.

At this point, I am going to analyze the libvlc.dll I have by seeing if it is valid or not by opening it in possibly VSC. Perhaps downloading the file may have had some corruption. I am not sure, but this could be the only possible way because VLCJ or VLC itself cannot cause it, the path is valid, and the mediaInstance variable isn't null.

PulseBeat02 commented 3 years ago

Wow. I am stupid! I just realized I set the path for VLC_PLUGIN_PATH to the wrong path. I am so sorry for wasting your time. That seemed to fix it all.

caprica commented 3 years ago

Well, OK, but with the correct usage of vlcj setting VLC_PLUGIN_PATH should never be needed.

PulseBeat02 commented 3 years ago

I was using a custom installation where I had the binaries installed (but they are in a different location). So I was just doing the loading process manually this way. Do you know the proper way to do it if the binaries are located in another place?

caprica commented 3 years ago

Write a custom DiscoveryDirectoryProvider and drop it in your classpath (uses the Java Service Loader mechanism).

PulseBeat02 commented 3 years ago

Ah I see. Thank you!