How can I play Video Files using VLCJ and JavaFX? - java

I'm aware that JavaFX has it's own media player, but I do not know if it can play MP4 files.
Even if it could, I would still prefer to use VLCJ as VLC supports more formats and varieties than I can count in my near-catatonic state.
I've followed the example posted by Caprical in his VLCJ-JavaFX GitHub but it does, well, nothing.
It doesn't error, but it does nothing.
Looking into the code, it seems the issue is in the Timeline event handler:
private final EventHandler<ActionEvent> nextFrame = new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
Memory[] nativeBuffers = mediaPlayerComponent.getMediaPlayer().lock();
if (nativeBuffers != null) { //<-----This is always NULL so everything in the block is skipped . . .
// FIXME there may be more efficient ways to do this...
// Since this is now being called by a specific rendering time, independent of the native video callbacks being
// invoked, some more defensive conditional checks are needed
Memory nativeBuffer = nativeBuffers[0];
if (nativeBuffer != null) {
ByteBuffer byteBuffer = nativeBuffer.getByteBuffer(0, nativeBuffer.size());
BufferFormat bufferFormat = ((DefaultDirectMediaPlayer) mediaPlayerComponent.getMediaPlayer()).getBufferFormat();
if (bufferFormat.getWidth() > 0 && bufferFormat.getHeight() > 0) {
pixelWriter.setPixels(0, 0, bufferFormat.getWidth(), bufferFormat.getHeight(), pixelFormat, byteBuffer, bufferFormat.getPitches()[0]);
}
}
}
mediaPlayerComponent.getMediaPlayer().unlock();
};
};
It's been suggested I get the logs but that will have to wait as I'm slipping into unconsciousness as I make this post (when I return to the land of the living, I will see about what I can do to post some). If there is a better way to make this happen, I'm all for it if someone can direct me there. Thanks...

The vlcj-javafx sample on the Github project works just fine.
You say in your question that vlcj "doesn't error, but it does nothing".
Well, there are two ways to check for errors which you don't show in the code you posted in your question.
The mediaPlayer.playMedia() method returns a boolean to say whether VLC accepted your MRL or not - did you check the return value? Note that even if this method returns true, it does not categorically mean VLC could play your media, but if it returns false it categorically means it could not be played.
You should add a MediaPlayerEventLister to your media player and provide implementations for "playing()" and "error()". These callbacks will be triggered asynchronously - because that's how LibVLC works - only then can you conclude whether vlcj "doesn't error", or "does nothing".
I suspect your media failed to start, probably because of a wrong filename.

Related

LibGDX App Hanging on initializGlfw()

I noticed that recently when I run my LibGDX game it takes a good 20 seconds to boot up which is strange because I'm only loading a few resources. I put breakpoints in my main method to pinpoint where the app was getting stuck, and it turns out it's getting stuck when I call this line:
new Lwjgl3Application(new GdxGame(), config);
In the Lwjgl3Application constructor, it is hanging on this method call:
initializeGlfw();
Which looks like this:
static void initializeGlfw() {
if (errorCallback == null) {
Lwjgl3NativesLoader.load();
errorCallback = GLFWErrorCallback.createPrint(System.err);
GLFW.glfwSetErrorCallback(errorCallback);
if (!GLFW.glfwInit()) {
throw new GdxRuntimeException("Unable to initialize GLFW");
}
}
}
In this method it gets stuck on createPrint and GLFW.glfwInit(). The print method looks like this:
public static GLFWErrorCallback createPrint(PrintStream stream) {
return new GLFWErrorCallback() {
private Map<Integer, String> ERROR_CODES = APIUtil.apiClassTokens((field, value) -> 0x10000 < value && value < 0x20000, null, GLFW.class);
#Override
public void invoke(int error, long description) {
String msg = getDescription(description);
stream.printf("[LWJGL] %s error\n", ERROR_CODES.get(error));
stream.println("\tDescription : " + msg);
stream.println("\tStacktrace :");
StackTraceElement[] stack = Thread.currentThread().getStackTrace();
for ( int i = 4; i < stack.length; i++ ) {
stream.print("\t\t");
stream.println(stack[i].toString());
}
}
};
}
All of these methods come from the Lwjgl library. Does anybody know why my app might be getting stuck on these method calls?
I've had the same issue and it seams to be tied to the machine you are on. I made a clean VS15 solution with GLFW and ran it on several different PCs to find that only my desktop had this issue. I also tested the LWJGL binding of GLFW and had the same results.
[EDIT] the wait happens in the glfwInit() call
/* Initialize the library */
if (!glfwInit()) // stuck here
return -1;
/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(1920, 1080, "Hello World", NULL, NULL);
There is one post that I came across an archived post on the openGL forums that mentions an issue similar to this but it's fairly old and might be referring to a slightly different issue.
I can recommend to check that you are excluding your build folder from any antivirus, sometimes they see the generated executables as potential threats and thus might be slow however i dont believe that's your issue.
Sadly the only option that has worked for me was a clean install of windows, though the bug mysteriously stopped manifesting itself when I connected a VR headset and reappeared a couple days later. Hope you have better luck than me and dont have to clean install your OS and if you find a less cumbersome solution be sure to spread the word.

"Cannot perform this action on a not sealed instance" java.lang.IllegalStateException exception

With android AccessibilityService able to paste in other app EditText Field, but with browser testfields (Emulator Default Browser or Samsung deault Browser) its not working, throwing error:
Cannot perform this action on a not sealed instance.
In android chrome browser with some singnup textfield its working but not for all textfields.
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
AccessibilityNodeInfo source = event.getSource();
if (source != null && ( event.getEventType() == AccessibilityEvent.TYPE_VIEW_FOCUSED ) ) {
// || event.getEventType() == AccessibilityEvent.TYPE_VIEW_CLICKED ) &&
//event.getClassName().equals("android.widget.EditText")
//) {
ctx = getApplicationContext();
ClipboardManager clipboard = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("label", "XYZ");
clipboard.setPrimaryClip(clip);
source.performAction(AccessibilityNodeInfo.ACTION_PASTE);
//Not Working, always return false.
//Tried with other options
Bundle argumentsTest = new Bundle();
argumentsTest.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "Bundle Test Data");
source.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT,argumentsTest )
// Not Working, throw java.lang.IllegalStateException exception
//Message: "Cannot perform this action on a not sealed instance"
}
}
I don't beleive you're trying to do what you think you're trying to do.
When you set the "text" of an accessibilityNodeInfo, what you're chaning is the text property of that object, as it pertains to your accessibility service. THIS DOES NOT mean, that you are changing the text of the EditText box, that the accessibilityNodeInfo object references. By the time your accessibility service gets this object, the two objects are quite separate from each other. Even if your code were to run successfully, you would not be getting the results you are expecting. Now, as for why you cannot perform this action, knowing this it should be obvious. For an accessibility service to be able to modify the nodes it has, doesn't really make sense. So they become sealed (think of this as a run time enforcement of a constant). Accessibility nodes become sealed and unsealed at various points in their lifetime. The parts of the framework that have access to unsealed node infos are View classes and private APIs. Any accessibility service related tasks are going to be dealing with sealed, read-only instances.
As for why your original solution is not working, I believe that we do not have enough information. The "ACTION_PASTE" approach is (approximately) the correct approach, HOWEVER, there are an abundance of issues when doing so with web browsers. Browser version, Android version, device version, website, etc all play a role. Especially if your set up is old enough to not use the new WebView (pure chromium webview, rather than the old 4.+ approach of odd embedded mobile WebViews based on outdated versions of WebKit, which will now never be updated). I recommend testing your code on an up to date Nexus device, using at least Android 5.0 and seeing if your code works. If you cannot do this, report version information for your set up. If you already are, on what website?

How do I get a VLC Media Player in Java without a Displayable Component?

I'm working with the VLCJ Bindings and have finally been able to get several roadblocks. Now I am here.
I have no need (at this time), nor desire for, a visible Media Player component (the EmbeddedMediaPlayerComponent). All I need (for now) is to play Audio Files.
I have the following method in place to handle that for me:
public static void Play(File AudioFile){
if (!LibVLCLoader.Loaded) LibVLCLoader.loadLibVLC();
EmbeddedMediaPlayerComponent EMPC = new EmbeddedMediaPlayerComponent();
if (EMPC.getMediaPlayer().prepareMedia(AudioFile.getAbsolutePath())){
EMPC.getMediaPlayer().addMediaPlayerEventListener(new MediaPlayerEventAdapter(){
#Override public void subItemFinished(MediaPlayer p, int i){
EMPC.release(true);
}
});
Platform.runLater(() -> EMPC.getMediaPlayer().play());
}
}
But I keep getting this exception:
Exception in thread "JavaFX Application Thread" java.lang.IllegalStateException: The video surface component must be displayable
Which I understand. It makes sense. But I don't NEED it visible. I just need the sound. How can I make that happen?
EmbeddedMediaPlayer is only for the case where you want to literally embed a video surface inside your application.
If you just need audio, there's an AudioMediaPlayerComponent for expressly this purpose.
To create such a component, simply:
AudioMediaPlayerComponent audioMediaPlayerComponent =
new AudioMediaPlayerComponent();
You can subclass it, for example to customise behaviour and easily implement event handlers.
Using the so-called "component" media players gives you a slightly nicer/easier API than using the non-"component" media players that are created via the MediaPlayerFactory.
This works just fine if your media is an audio file.
If your media is actually video, but you only want to play the audio track, then even if you use the AudioMediaPlayerComponent by default VLC will open a video window. In this case you still need to actually disable the video output - the simplest way to do this is to tell VLC to use vcodec=dummy.
I really don't agree with tricks like creating a window and moving it off-screen, or sizing it down to 1x1, it's just not necessary.
In the code posted in the original question there is an unrelated problem. The EMPC and EMP variable will go out-of-scope when the Play() method terminates, making the media player eligible for garbage collection. What will happen is that some random time later your application will likely crash because the native hooks that vlcj uses will call back into a Java object that no longer exists. You need to keep your media player references alive via hard references.
Okay so it turns out you can create your own MediaPlayer object outside of the EmbeddedMediaPlayerComponent like so:
public static void Play(File AudioFile){
if (!LibVLCLoader.Loaded) LibVLCLoader.loadLibVLC();
MediaPlayerFactory MPF = new MediaPlayerFactory(
"--video-title=vlcj video output",
"--no-snapshot-preview",
"--quiet",
"--quiet-synchro",
"--sub-filter=logo:marq",
"--intf=dummy"
);
EmbeddedMediaPlayer EMP = MPF.newEmbeddedMediaPlayer();
if (EMP.prepareMedia(AudioFile.getAbsolutePath())){
EMP.addMediaPlayerEventListener(new MediaPlayerEventAdapter(){
#Override public void subItemFinished(MediaPlayer p, int i){
EMP.release();
MPF.release();
}
});
Platform.runLater(() -> EMP.play());
} else{
EMP.release();
MPF.release();
}
}

Hide Mouse Pointer on Android

I'm writing a game for OUYA and Android and I'm using the trackpad on the OUYA controller. When ever you touch it a mouse pointer comes up and I can't find a way to hide it. I image this would be a problem for games on an Android netbook as well.
Has anyone found a way to interact with the cursor instead of just listening for events?
This won't hide the mouse, but it will at least help prevent touch events from interfering with your joystick processing code -- not a proper solution I know, but still might help people who land on this page:
public boolean onGenericMotionEvent(MotionEvent event) {
if ( (event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
//handle the event
return true;
}
else {
return false;
}
}
Android currently does not expose any functionality to hide the mouse cursor. Whenever you have an external pointing device (ie. usb/bluetooth mouse, trackpad, etc) a mouse pointer will appear on the screen whenever you interact with the device.
Unfortunately (as of JB 4.2.2) this means it is impossible without a modified ROM.
It is possible to request pointer capture now. You need to explicitly request capture:
fun onClick(view: View) {
view.requestPointerCapture()
}
As documented:
Android delivers pointer events from sources other than the mouse normally, but the mouse pointer is not visible anymore.
You can either handle pointer events by overriding onCapturedPointerEvent:
override fun onCapturedPointerEvent(motionEvent: MotionEvent): Boolean {
// Get the coordinates required by your app
val verticalOffset: Float = motionEvent.y
// Use the coordinates to update your view and return true if the event was
// successfully processed
return true
}
or registering an event handler for OnCapturedPointerListener:
myView.setOnCapturedPointerListener { view, motionEvent ->
// Get the coordinates required by your app
val horizontalOffset: Float = motionEvent.x
// Use the coordinates to update your view and return true if the event was
// successfully processed
true
}
And it's up to you to release the pointer when you're done:
override fun onClick(view: View) {
view.releasePointerCapture()
}
I know that the context of this question overall may not apply (ie: Ouya development), but this was the first search result when I looked into how to do this myself. So I figured that I'd update the answer!

Playing sound on BlackBerry gives an error

I'm having trouble getting a short MP3 file to play in a very small app I'm writing to learn how to develop for the BlackBerry.
Because I'm a newbie at BlackBerry development, I've uploaded my Eclipse project for the app to http://stroke.sampablokuper.com/stroke.zip because I don't know if the problem's with my Java programming, or the way I've laid out the resources in my project, or something else.
It's a very small project - only one Java file & three media files - so please help me by seeing if you can run it without errors in the Curve 8520 simulator on your computer. (It's designed for the 8520, because that's the phone a friend of mine has; I don't have a BB myself - yet!)
The idea is that when the user presses/scrolls "down" on the trackball/pad, a sound will be played, but currently instead of the sound, I just get an error message: javax.microedition.media.MediaException .
I've tried to debug this, but as I say, I'm a total newbie to BB development, so I don't really know how to make sense of the information I get from the breakpoints I've set.
Please can you tell me where I've gone wrong?
I really want to finish this before Christmas; please help!
Thanks in advance :)
EDIT: here's the relevant portion of the code, stripped down as much as possible:
public boolean navigationMovement(int dx, int dy, int status, int time) {
if (dx == 0 && dy == 1)// DOWN
{
makeNoise("growl");
}
return true;
}
private void makeNoise(String action) {
if (action == "growl") {
Dialog.alert("GROWL");
try
{
Player p = javax.microedition.media.Manager.createPlayer("growl.mp3");
p.realize();
VolumeControl volume = (VolumeControl)p.getControl("VolumeControl");
volume.setLevel(30);
p.prefetch();
p.start();
}
catch(MediaException me)
{
Dialog.alert(me.toString());
}
catch(IOException ioe)
{
Dialog.alert(ioe.toString());
}
}
invalidate();
}
Further edit I've removed the link to download the project, since the problem did indeed appear to be with the code, and is now solved anyway.
if you have mp3 file on SDCard your URI should be file:///SDCard/<file>.mp3 but if you are playing it from application then getResourceAsStream is the answer
The problem turned out to be that the string passed to the .createPlayer method needs to be a URI.
I tried many variations along the lines file:///growl.mp3 before eventually giving up (if anyone knows the correct URI syntax for pointing to a file within a BlackBerry App, please comment!) and settling on this:
InputStream is = getClass().getResourceAsStream("growl.mp3");
Player p = javax.microedition.media.Manager.createPlayer(is,"audio/mp3");
It's a bit crufty by comparison, but at least it works!

Categories

Resources