Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Can't load JAWT" on Oracle Java 7 for OS X #205

Closed
davidfstr opened this issue Sep 7, 2013 · 34 comments
Closed

"Can't load JAWT" on Oracle Java 7 for OS X #205

davidfstr opened this issue Sep 7, 2013 · 34 comments
Labels

Comments

@davidfstr
Copy link

Environment: vlcj 2.4.1, Oracle Java 7, OS X 10.7, vlc 2.0.0

Summary: DefaultMediaPlayer.playMedia() throws a java.lang.UnsatisfiedLinkError: Can't load JAWT exception when using Oracle Java 7 on OS X. Apple Java 6 works.

Repro Steps:

  • Install a fresh copy of OS X 10.7 on physical hardware.
    • Virtualizing it inside Parallels does not work because VLC needs hardware acceleration support to play certain videos and my version of Parallels does not provide hardware acceleration.
  • Install the JDK for Oracle Java 7.
  • Install VLC 2.0.0 in /Applications/vlc-2.0.0.
  • Install VLCJ 2.4.1 and add its JAR to your $CLASSPATH.
  • Copy the Tutorial2B.java code to a local file.
  • javac Tutorial2B.java
  • java Tutorial2B TestVideo.m4v

Expected Results:
A window appears and the specified video plays inside of it.

Actual Results:
A black window appears. The following stack trace is printed:

$ java Tutorial2B TestVideo.m4v 
JavaVM WARNING: JAWT_GetAWT must be called after loading a JVM
Exception in thread "AWT-EventQueue-0" java.lang.UnsatisfiedLinkError: Can't load JAWT
    at com.sun.jna.Native.getWindowHandle0(Native Method)
    at com.sun.jna.Native$AWT.getComponentID(Native.java:1879)
    at com.sun.jna.Native.getComponentID(Native.java:253)
    at uk.co.caprica.vlcj.player.embedded.videosurface.CanvasVideoSurface.attach(CanvasVideoSurface.java:69)
    at uk.co.caprica.vlcj.player.embedded.DefaultEmbeddedMediaPlayer.attachVideoSurface(DefaultEmbeddedMediaPlayer.java:156)
    at uk.co.caprica.vlcj.player.embedded.DefaultEmbeddedMediaPlayer.onBeforePlay(DefaultEmbeddedMediaPlayer.java:315)
    at uk.co.caprica.vlcj.player.DefaultMediaPlayer.play(DefaultMediaPlayer.java:696)
    at uk.co.caprica.vlcj.player.DefaultMediaPlayer.playMedia(DefaultMediaPlayer.java:213)
    at Tutorial2B.<init>(Tutorial2B.java:46)
    at Tutorial2B.<init>(Tutorial2B.java:13)
    at Tutorial2B$1.run(Tutorial2B.java:29)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
    at java.awt.EventQueue.access$200(EventQueue.java:103)
    at java.awt.EventQueue$3.run(EventQueue.java:694)
    at java.awt.EventQueue$3.run(EventQueue.java:692)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:703)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)

Notes: This exact same code works correctly when run on Apple Java 6. Therefore Oracle broke something during their port. I have run all tests on fresh installs of OS X 10.7 so there isn't anything else in my environment that would be causing conflicts.

@caprica
Copy link
Owner

caprica commented Sep 7, 2013

See #131, at least the later comments, and in particular:

#131 (comment)

Your last point is the most pertinent and I do not know of any solution.

@caprica
Copy link
Owner

caprica commented Sep 7, 2013

By the way, you can trigger the "bug" simply by invoking Native.getComponentId(canvas)... no vlcj code is neeed at all to trigger it.

@davidfstr
Copy link
Author

So if you can use JDK 1.6, you should try vlc 2.0.7.

Not possible unfortunately. The only reason I am looking at VLCJ is because I am migrating away from the deprecated QuickTime for Java bindings that no longer work on Java 7. I want to use an API that has some degree of future-proofing.

Otherwise there is nothing that can ever be fixed in vlc/vlcj to get native video rendering - it is a platform/JDK issue and I believe it is by design, not a bug.

To your knowledge has a bug been filed on Oracle? It seems that not having an API to access native NSViews would preclude any third party visual components from interfacing with AWT / Swing / JavaFX. I would think that would be considered a serious issue by Oracle.

@davidfstr
Copy link
Author

So here's the timeline of events I've been able to reconstruct, after a great deal of reading:

  • (1) When Oracle ported Apple's Java 6 to Oracle's Java 7, they removed the API that provided the NSView backing an AWT Canvas view. It appears this was done because there was no longer in fact an NSView backing AWT views: AWT views were converted from heavyweight components to lightweight components in Java 7.
  • (2) Simultaneously Oracle failed to provide API access to the CALayer underlying AWT views, which Apple originally provided access to via an API introduced in OS X 10.6 Java Update 9. This might also have been due to AWT views no longer being heavyweight.
    • It is not clear whether this API omission was deliberate or not, as there is an unresolved workitem to fix this. That workitem has not seen activity since Sep 2011 so I must presume Oracle doesn't care about it.
    • The LWJGL project manually used JNI to access this API directly but ran into issues. In the end it appears they reimplemented everything to call Cocoa APIs directly through JNI, eschewing AWT entirely.
  • (3) Both (1) and (2) in combination means there is no API in Java 7 for accessing a native backing view for any AWT view. This means that it is not possible for code that needs to draw into an NSView or CALayer to interoperate with AWT (or Swing or JavaFx).

Also of interest:

  • Manual inspection of the JAWT library headers, which historically have provided access to the native NSView / CALayer underlying an AWT view, reveal that there is an API to access a native X11 drawing surface for an AWT view. I find this surprising since I'm fairly sure that AWT views are not in any way backed by X11 drawing surfaces. My guess is that these headers were blindly copied from Oracle's Solaris Java and not actually implemented on OS X.

Your last point is the most pertinent and I do not know of any solution.

Based on this statement I'm guessing you're not planning on employing extraordinary efforts to fix this issue on OS X in advance of Oracle providing an API to make a fix reasonable. And it doesn't look like Oracle is interested in making a fix, given their lack of updates to the related workitem. Therefore VLCJ will not support the latest versions of OS X & Java for the foreseeable future unless someone else steps up to make a fix.

And I'm not willing to be that guy since it will (probably) be faster to rewrite my Java application to use a different rendering mechanism (such as HTML).

Depending on your GitHub Issue workflow you could leave this Issue open (as a known issue). Or otherwise migrate this known issue to somewhere in your documentation.

@caprica
Copy link
Owner

caprica commented Sep 7, 2013

I'm guessing you're not planning on employing extraordinary efforts to fix this issue on OS X in advance of Oracle providing an API to make a fix reasonable.

I can not imagine what any such "extraordinary efforts" might be. Please elaborate if you think it's possible, I doubt it.

With vlcj, you can always fall back to the direct rendering approach. Not ideal, but it works. In any event it's seemingly Hobson's choice.

@caprica caprica closed this as completed Sep 7, 2013
@davidfstr
Copy link
Author

I can not imagine what any such "extraordinary efforts" might be.

I was thinking along the lines of forcefully pulling out the NSView or CALayer out of Oracle's AWT implementation through private API. This maintains the VLCJ ability to compose with AWT and Swing views. Naturally this approach is very brittle.

The other option I see is rewriting VLCJ to use a different rendering platform than AWT or Swing that provides better access to the native NSView & CALayer objects. SWT looks promising, as the native integration documentation looks quite approachable. But changing the rendering platform completely breaks backwards compatibility with existing clients of VLCJ and thus is a nonstarter.

@caprica
Copy link
Owner

caprica commented Sep 8, 2013

The essential point I think is this: libvlc (not vlcj), when embedding, requires a native heavyweight window handle to render video. vlcj does not render the video, vlc renders it, so suggesting that vlcj be rewritten to use a different rendering platform does not make sense to me.

If you can't provide a heavyweight window handle, then you are left with using vlcj with direct rendering or finding some other solution.

Anything else is outside the scope of this project.

@caprica
Copy link
Owner

caprica commented Sep 8, 2013

Maybe this relates somehow, I don't know:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7181710

Might be worth testing jdk7u40 when it is released, at time of writing it's early access downloadable from here:

http://jdk7.java.net/download.html

@davidfstr
Copy link
Author

Well that's definitely a step in the right direction. If the header file to be restored is as described in the bug then Oracle has silently implemented the API that provides the native CALayer behind an AWT view.

From your description of VLC's API, we'd need to actually get an NSView to pass to VLC. There's a reasonable chance that VLC's API could be extended take a CALayer as an alternative to an NSView, since both provide a native drawing surface. I might be willing to take on that API extension if that's all that would be needed from VLC's side.

@caprica
Copy link
Owner

caprica commented Sep 10, 2013

Might be worth testing the developer preview of JDK8 that was very recently published:

http://jdk8.java.net/download.html

@caprica
Copy link
Owner

caprica commented Sep 14, 2013

JDK7u40 is now released, this supposedly includes the fix mentioned in an earlier comment.

http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html

Might be worth a try.

@viniciusgava
Copy link

I have same problem, using JDK7u40.

@caprica
Copy link
Owner

caprica commented Sep 17, 2013

Thanks for testing that.

Unfortunately this means it will likely never work. At least not without some major native code for Mac. That's outside the scope of this project.

@hanxue
Copy link

hanxue commented Nov 29, 2013

An update that it does not work with java 1.8.0-ea on OS X Mavericks with the same error:

java.lang.UnsatisfiedLinkError: Can't load JAWT

@caprica
Copy link
Owner

caprica commented Nov 29, 2013

I don't think this will ever work on OSX again. The change in philosophy for AWT on OSX was made intentionally.

@caprica
Copy link
Owner

caprica commented Dec 19, 2013

Maybe these reports relate, still no sign of any fix as far as I can tell:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7154778
https://bugs.eclipse.org/bugs/show_bug.cgi?id=374199

@caprica
Copy link
Owner

caprica commented Apr 3, 2014

Interesting approach using Wine here:

https://www.youtube.com/watch?v=sGkHINJvhTw

It was posted April 1st, but I think it's real... ;-)

@caprica
Copy link
Owner

caprica commented Feb 1, 2015

There's still no satisfactory answer for this.

I note that SWT has apparently been made to work:

This bug relates https://bugs.eclipse.org/bugs/show_bug.cgi?id=374199

This seems to hinge around CViewEmbeddedFrame, but after some investigations and testing I can't quite understand if it will be useful for this issue in vlcj or not.

If the SWT_AWT bridge still works on JDK 1.7 and 1.8, then in theory vlcj in SWT is an option (albeit far from ideal) for for OSX.

@caprica
Copy link
Owner

caprica commented Feb 9, 2015

See also https://bugs.eclipse.org/bugs/show_bug.cgi?id=418245.

No answers.

@caprica
Copy link
Owner

caprica commented Feb 9, 2015

Also http://mail.openjdk.java.net/pipermail/awt-dev/2013-December/006711.html.

What I find hilariously depressing about this is that according to that mailing list thread the justification for this is "because applets" and "because web browsers".

Who really cares about the sub-standard Java applets experience nowadays when HTML5 is so superior, especially with applets as a significant attack vector.

@caprica
Copy link
Owner

caprica commented Feb 9, 2015

I don't know if this will help, but there is a new "caopengllayer" video output in VLC 2.2.0 that also allows to set a video surface with libvlc_media_player_set_nsobject.

I can't investigate this further until VLC 2.2.0 final is released.

@caprica
Copy link
Owner

caprica commented Mar 21, 2015

In my testing, I can't do anything with the caopengllayer video output from Java. It is still totally unknown what should be used for the nsobject parameter value.

This is effectively a dead end, and native rendering on OSX after Java 6 looks pretty much a bust unless someone else posts some useful information.

@caprica
Copy link
Owner

caprica commented Jul 26, 2015

In the impossible quest to find a solution to this, another tidbit...

From https://groups.google.com/a/teamdev.com/forum/#!topic/jxbrowser-forum/CgGX76sHfCA:

private static long getNSWindowViewPtr(Window window) {
    try {
        Object componentPeer = window.getClass().getMethod("getPeer").invoke(window);
        Object platformWindow = componentPeer.getClass().getMethod("getPlatformWindow").invoke(componentPeer);
        Object contentView = platformWindow.getClass().getMethod("getContentView").invoke(platformWindow);
        return (Long) contentView.getClass().getMethod("getAWTView").invoke(contentView);
    } catch (Exception exception) {
        throw new RuntimeException(exception);
    }
}

@caprica
Copy link
Owner

caprica commented Sep 3, 2015

Right now I think that SWT is the only way to get this working on OSX on any JDK after 1.6.

SWT and Swing can co-exist, so using SWT for video and Swing for everything else (if that's what is wanted) is probably the best that can be done here.

I think that approach would be better in terms of performance than using a direct media player.

@caprica
Copy link
Owner

caprica commented Mar 27, 2016

Example showing how to embed vlcj inside SWT that is itself embedded inside a Swing applicaiton at https://github.com/caprica/vlcj-swt-swing

@caprica
Copy link
Owner

caprica commented Mar 28, 2016

Example showing how to embed vlcj inside SWT, not using Swing, at https://github.com/caprica/vlcj-swt-demo

@ryantheseer
Copy link

FYI: I'm trying to make my VLCJ-based RTSP streamer work cross-platform on Windows, Mac and Linux. Windows is working fine, but I'm running into this same issue. However, when I try to use the SWT Composite solution, the new swt.jar I can download from the website (v 4.7.1a) has hidden the "embeddedHandle" property of the Composite object. I am trying with v 4.5.2, as you've included in your pom.xml maven build file, but it seems to have the same issue... Not sure if I want to modify the Composite.java source code to gain access...

@caprica
Copy link
Owner

caprica commented Oct 26, 2017

Ultimately, a native window handle is needed by LibVLC - if the toolkit you use does not provide an official/public API to get that handle, you must resort to workarounds. The least bad workaround is to use reflection to e.g. make a private native window handle class field public instead, and extract that value. If that's not possible, then... good luck.

This particular issue is very difficult to do anything about.

@ivanooi
Copy link

ivanooi commented Dec 28, 2018

found this code to get the Composite handle. it work with JDK8
replace this
long componentId = composite.embeddedHandle;

with this
long componentId = getControlHandle( composite );

https://stackoverflow.com/questions/29889540/how-to-get-the-handle-of-swt-control-in-mac-64-bit-cocoa-enviornment

@caprica
Copy link
Owner

caprica commented Dec 28, 2018

Any idea if this works on later JDKs, i.e. 9, 10, 11?

Having said that, if it does indeed work on at least JDK 8, it will be definitely be worth putting that code into vlcj itself.

@caprica caprica reopened this Dec 28, 2018
@ivanooi
Copy link

ivanooi commented Dec 28, 2018

my current setting. 10.13.6, Eclipse Neon, JDK8. didn't try 9, 10 or 11.....
only one problem.. sometimes image did not auto resize according to the window... not sure is it VLC problem or others.... so far so good

@caprica
Copy link
Owner

caprica commented Dec 29, 2018

Oh, I just realised this was in relation to SWT. Damn. I was hoping it was finally a solution for using Canvas on OSX but it's clearly not.

@caprica caprica closed this as completed Dec 29, 2018
@ivanooi
Copy link

ivanooi commented Dec 29, 2018

hahaha well, rather than VLCJ totally dead in OS X. that what happen when i tried to run it in OS X....now because of SWT, VLCJ back to business

@caprica
Copy link
Owner

caprica commented Sep 5, 2020

Linking this purely for reference, as it seems somewhat related and interesting:

LWJGLX/lwjgl3-awt#1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants