I have written a code using vlcj which is intended to take screenshots of a video periodically. When I try to output the length of the video, it prints 0. What is the issue ?
import uk.co.caprica.vlcj.binding.LibVlc;
import uk.co.caprica.vlcj.player.MediaPlayerFactory;
import uk.co.caprica.vlcj.player.embedded.EmbeddedMediaPlayer;
import uk.co.caprica.vlcj.runtime.RuntimeUtil;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
public class ScreenShotCapture {
public static void main(String[] args){
NativeLibrary.addSearchPath(RuntimeUtil.getLibVlcLibraryName(), "C:\\Program Files\\VideoLAN\\VLC");
Native.loadLibrary(RuntimeUtil.getLibVlcLibraryName(), LibVlc.class);
MediaPlayerFactory mediaPlayerFactory = new MediaPlayerFactory();
final EmbeddedMediaPlayer mediaPlayer =mediaPlayerFactory.newEmbeddedMediaPlayer();
mediaPlayer.playMedia("E:\\videos\\Avenged Sevenfold - So Far Away [Music Video].mp4");
mediaPlayer.setSnapshotDirectory("E:\\vidoes");
long length = mediaPlayer.getTime();
long interval = length / 21;
for(long i = 1;i <= length;i+= interval){
mediaPlayer.setTime(i);
mediaPlayer.saveSnapshot();
}
}
}
The media length is not immediately available, it will become available some time after the media has started playing when the decoder works out what the length is. That is just inherently how VLC works.
Just about everything works asynchronously, which means you must base your code on events rather than writing code in only a procedural way.
When the length changes a native event gets generated, ultimately causing a MediaPlayerEventListener#lengthChanged event to fire. When that event has fired, the call to mediaPlayer.getLength() should return a non-zero value.
The next issue is that you invoke saveSnapshot immediately after you invoke setTime. Again, setTime works asynchronously so you can not assume that the media player has reached the desired time when that method returns. You have to wait for a timeChanged event and check if your time has been reached (actually passed) yet or not.
The final issue, that may or may not be important depending on your use-case, is that the call to saveSnapshot is itself asynchronous so essentially you have requested a snapshot but it has not been generated yet. This time you need to wait for the snapshotTaken event. Only when that event has been received has the snapshot actually been saved to disk.
So basically you need to think differently and implement an event-based approach instead.
One example of that is in this vlcj example that generates snapshots: https://github.com/caprica/vlcj/blob/vlcj-3.0.1/src/test/java/uk/co/caprica/vlcj/test/condition/ConditionTest.java
If you don't like that example, then you can implement it just by responding to the events in your own MediaPlayerEventListener implementation.
An aside: you can also use the VLC "Scene" filter to generate snapshots in a reliable way.
I assume it's not caused by your spelling mistake in setting the snapshot directory?
Related
I'm working on Java APP that will process the stream from the IP Camera (Milesight MS-C2682-P) located on Local network. It will detect objects and trigger actions depending on what's in the image (let´s say it will start an alarm, when a person is detected) - for that I need it to be with minimal delay.
I have an RTSP link "rtsp://username:password#ip_addr:rtsp_port/main", to access stream from my IP Camera, but in my JAVA app there is a 12 seconds delay (and it's increasing). This happens, when images are not handled fast enough, so they are buffered. There are "hacks" and "workarounds" (OpenCV VideoCapture lag due to the capture buffer), but I believe there has to be a prettier solution.
The other link I was able to get is an HTTP one, that uses also H.264 codec (can be used with MJPEG and MPEG4, if there is a possible way to use them effectively). "http://username:password#ip_addr:http_port/ipcam/mjpeg.cgi" - works like a charm.. in Python and browser. However, it doesn´t work in Java, an error is thrown:
OpenCV(4.2.0) C:\build\master_winpack-bindings-win64-vc14-static\opencv\modules\videoio\src\cap_images.cpp:253: error: (-5:Bad argument) CAP_IMAGES: can't find starting number (in the name of file): HTTP_URL in function 'cv::icvExtractPattern'
Both links work smoothly in VLC.
So, the network is not a problem ('cause VLC handles stream with minimal delay) and Python using OpenCV is also doing a good job. It all comes down to Java implementation of OpenCV.. I guess.
Here is a Java code:
VideoPlayer videoPlayer = new VideoPlayer(); // My Class, just creates and updates JFrame, works like a charm with laptop's webcam, so certainly no issues here
Mat image = new Mat();
VideoCapture ipCamera = new VideoCapture(RTSP_URL);
// or the HTTP link
// VideoCapture ipCamera = new VideoCapture(HTTP_URL);
// verify if u got access to camera
if (!ipCamera.isOpened()) {
System.out.println("ERROR: Camera isn't working !!! ");
return;
}
System.out.println("OK: Connected to camera.");
while (true) {
ipCamera.read(image);
videoPlayer.updateVideo_MatImage(image);
}
And this is the Python code I'm using:
import cv2
cap = cv2.VideoCapture(RTSP_URL)
# or the HTTP link
# cap = cv2.VideoCapture(HTTP_URL)
while True:
ret, image = cap.read()
cv2.imshow("Test", image)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
I just need to get the latest image, when a request is made. So I need to avoid any kind of buffering. It has to be implemented in Java since it's a requirement for this project.
So is there a way to get only latest image from camera?
What could cause the error mentioned above?
Thank you guys for any advice.
When making the application full screen with the following call:
Gdx.graphics.setFullscreenMode(Gdx.graphics.getDisplayMode());
I no longer have signals from my controller. The issue is not solved by changing the display back from full screen like:
Gdx.graphics.setWindowedMode(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2);
I'm using Gdx version: 1.9.8. It appears this was an issue fixed in a previous version, but I'm not sure what the necessary steps are to get the work around functioning.
Here's some posts I found about the issue:
https://github.com/libgdx/libgdx/issues/4723
https://github.com/GoranM/bdx/issues/518
(this one is old) http://www.badlogicgames.com/forum/viewtopic.php?f=11&t=10692
Any help is much appreciated.
*Edit: This is using the controller extension that can be checked from the libgdx set up application. *
Edit2: I can get a responsive controller if I re-poll the controllers like the following:
Array<Controller> controllers = Controllers.getControllers();
However, this cannot be done instantly after changing the display mode; I have to wait some amount of time after. I'm not sure what I need to poll to determine how long I have to wait until the controller instances are valid (also, when it is valid to assign a listener).
Edit3: The only solution I've been able to come up with is to set a flag inside the resize callback like the following
#Override
public void resize(int width, int height) {
resizeDirty = true;
resizeTimestamp = System.currentTimeMillis();
}
Then in my main loop call:
private void controllerCheck() {
if (resizeDirty) {
long currentTime = System.currentTimeMillis();
if (currentTime > resizeTimestamp + controllerResetDelay) {
resizeDirty = false;
//get new controller instance | re-add a controller listener
}
}
}
This isn't ideal, I'd rather find a way to listen to when the change in context is done initializing then update the controllers. But I haven't been able to find a hook for that. I'd appreciate it if anyone knows a better way to go about maintaining controllers with change in display mode.
Why don't you try to use the immersive fullscreen?
If the objective is to set the fullscreen mode, I think this is the better way to.
The GWT web app I'm building has a page where users can upload CSV files. The upload code uses the Moxieapps GWT Uploader, which mostly works great.
However, I've discovered a strange scenario, where navigating away from the page and back to it adds the upload button again. So the third time I visit the page, the upload section will look like this:
And the relevant part of the generated HTML viewed in an inspector shows that both the input and the div containing the "button" get added over and over (though there is only ever one dropzone):
I've gone over my code many times to see whether I was doing something that could be causing this, but haven't found anything. You don't actually manually add the button or the input; this is done automatically by the framework. The fileUploader gets initialised only once (this being GWT client code, I've debugged using the inspector as well as logging statements to the console to confirm this):
fileUploader.setButtonDisabled(true).setFileTypes("*.csv")
.setUploadURL(getBaseUrl() + "/fileUpload.upload")
.setButtonText("<span class=\"buttonText\">Select CSV file to upload</span>")
.setFileSizeLimit(FILE_SIZE_LIMIT)
.setButtonCursor(CustomUploader.Cursor.HAND)
.setButtonAction(CustomUploader.ButtonAction.SELECT_FILE)
.setUploadProgressHandler(new UploadProgressHandler() {...})
.setUploadSuccessHandler(...)
// etc. with other handlers
The method setButtonText() is called from a couple of other places, and the text changes as it should, but only on the last button (if there are several). Otherwise, there's nothing in my code that could possibly be adding the button as far as I can tell.
Has anyone else encountered this issue? Is there some property I need to set to prevent this? Could it be a bug in the moxieapps code?
After writing out my question, and adding "Could it be a bug in the moxieapps code?" at the end, I followed up on that suspicion, and it turns out that it is indeed a bug in the org.moxieapps.gwt.uploader.client.Uploader class.
The input and the "select file" button are added in the onLoad() method of that class without a check whether they may have been added already.
It looks like there hasn't been any active development on this framework for some time, so I thought it was time for a custom override version. I've tested this and it works:
package yourpackagename.client.override;
import java.util.Iterator;
import org.moxieapps.gwt.uploader.client.Uploader;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.WidgetCollection;
/**
* The sole reason this class exists is to fix a bug in the moxieapps uploader
* (org.moxieapps.gwt.uploader-1.1.0.jar) where it adds a new upload input and
* button each time its <code>onLoad()</code> method is called, i.e. every time
* you navigate away from the page and then back to it.
*/
public class CustomUploader extends Uploader {
#Override
protected void onLoad() {
boolean hasFileUploadAlready = false;
WidgetCollection children = getChildren();
for (Iterator<Widget> iterator = children.iterator(); iterator.hasNext();) {
Widget eachWidget = iterator.next();
if (eachWidget instanceof FileUpload) {
hasFileUploadAlready = true;
}
}
// Only call the super method if there isn't already a file upload input and button
if (!hasFileUploadAlready) {
super.onLoad();
}
}
}
Instead of referencing the org.moxieapps.gwt.uploader.client.Uploader, I've changed the references to point to my custom uploader class, which will now check for an existing FileUpload child widget, and simply skip the original onLoad() code if it finds such a widget.
Might be a bit of a crowbar approach, but it works (and in my case, changing the maven-managed JAR file is not very practical). Hopefully, this will be useful to anyone else coming across this problem.
I am trying a java desktop application(I am a student).
It have to deal with four kinds data during start up:
1)project tree(like eclipse Project tree) view data.
Currently I using XMLEncoder/XMLDecoder to save and reload from XML file.
2)user preferences data. such as font,recently files and so on.
Currently I using java.util.prefs.Preferences.
3)Class data .Some factory class like MenuFactory,util class like DatabaseUtil,FileUtil and so on they have some static data.
Currently I using static initializer in these class to initialize default data.
4)Database-related information,such as connection configuration,frequently used database name and table names.
Currently I using java.util.Properties;
What I want to improve:
1) Is it the right way to save my application data in those four kinds mentioned above ?
2)since there are so many data to load,what should I do during a splash screen.
To load them at start up time or delayed to the time when using them ?
At least,I do not want to deceive user by using the following code(not updating progress bar at a meaningful time):
SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() {
#Override
protected Void doInBackground() throws Exception {
for (int i = 0; i < 50; i++) {
Thread.sleep(100);// Simulate loading
publish(i*2);// Notify progress
}
return null;
}
3) I think too many static initializer may slowdown the program start up ,any suggestion?
If your app is targeted for high end devices then you can certainly load most of it during the startup/splash screen.
But the issue comes when you have low end devices as well as your target devices. For some of the low end devices loading too much data at startup leaves very less memory for other processing. Some imd leading to even crashing.
Thus it a decision which you have to take wisely and if it some small data then better leave for loading as per required or while that screen is loaded.
I have to create an application that will automatically open a powerpoint file, let it play through, and then close it. Not only do I need to figure out HOW to close it, but I also must detect when it closes or stops.
First option:
I know how long each powerpoint will play for, so I can hardcode when to close the file. I just need to know how to do that. There are no methods in the desktop class (that I could find) for closing.
Second option:
If someone knows a microsoft powerpoint api that lets me open powerpoints and use java to progress through the slideshow and get the state or something, that'd be great. I wouldn't have to go into each presentation and count the number of slides and the transition timer on each slide.
The opening, letting it play, and closing it is a small part of the app I need to create. But here is what I have so far with regards to THIS problem:
File myfile = new File("PowerPoint.ppsx");
try {
Desktop.getDesktop().open(myfile);
} catch (IOException ex) {
Logger.getLogger(Sc.class.getName()).log(Level.SEVERE, null, ex);
}
Probably this is the solution how to close external program:
http://www.java-forums.org/new-java/59691-close-another-program.html#post285956
If you want to detect when program has stopped running then you can start new thread with loop which from time to time will check if the program process is still running, using the same method as mentioned in link.
This is solution only for one (Windows) platform, Java is not the best choice for such tasks.
Here a solution using JNA. First we get the handle, we search using the "class name" of the window. You can determine the class name for a specific program (in this case Powerpoint) with a special utility like Spy++ (included with Visual Studio). It's possible to make the search more precise using the class name and the window caption (but here I use only the class name) so if you have more than one presentation running ... you may not close the good one!.
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinUser;
import com.sun.jna.platform.win32.WinDef.HWND;
// https://github.com/twall/jna#readme
// you need 2 jars : jna-3.5.1.jar and platform-3.5.1.jar
public class KillMyPP {
public static void main(String[] args) {
HWND hwnd = User32.INSTANCE.FindWindow("screenClass", null);
if (hwnd == null) {
System.out.println("PPSX is not running");
}
else {
User32.INSTANCE.PostMessage(hwnd, WinUser.WM_QUIT, null, null);
}
}
}