I'm using OpenCV for a object detection project. I'm trying to read frames from a stored video file using VideoCapture, but in OpenCV Java there is no current implementation. I followed instructions in this post: open video file with opencv java, to edit the source files of OpenCV Java to allow this functionality. The problem is I don't know how to recompile the files? - since I just added the downloaded opencv jar file into my eclipse project originally.
You should probably try JavaCV, an OpenCV wrapper for Java.
This post shows what you need to download/install to get things working on your system, but I'm sure you can find more updated posts around the Web.
One of the demos I present during my OpenCV mini-courses contains a source code that uses JavaCV to load a video file and display it on a window:
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_highgui.*;
import com.googlecode.javacv.OpenCVFrameGrabber;
import com.googlecode.javacv.FrameGrabber;
public class OpenCV_tut4
{
public static void main(String[] args)
{
FrameGrabber grabber = new OpenCVFrameGrabber("demo.avi");
if (grabber == null)
{
System.out.println("!!! Failed OpenCVFrameGrabber");
return;
}
cvNamedWindow("video_demo");
try
{
grabber.start(); // initialize video capture
IplImage frame = null;
while (true)
{
frame = grabber.grab(); // capture a single frame
if (frame == null)
{
System.out.println("!!! Failed grab");
break;
}
cvShowImage("video_demo", frame);
int key = cvWaitKey(33);
if (key == 27) // ESC was pressed, abort!
break;
}
}
catch (Exception e)
{
System.out.println("!!! An exception occurred");
}
}
}
Related
AIM: convert a PDF to base64 where PDF can be a general PDF or a scanned one.
I am using Tesseract OCR for converting scanned PDFs to text files. Since I am working in Java, I am using terr4j library for this.
The flow of program as I have thought would be as follows:
Get PDF file ---> Convert each page to image using Ghost4j ---> Pass each image to tess4f for OCR ---> convert whole text to base64.
I have been able to convert a PDF file to Images using following code:
package helpers;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.awt.Image;
import java.awt.image.RenderedImage;
import java.util.List;
import javax.imageio.ImageIO;
import org.ghost4j.document.DocumentException;
import org.ghost4j.document.PDFDocument;
import org.ghost4j.analyzer.FontAnalyzer;
import org.ghost4j.renderer.RendererException;
import org.ghost4j.renderer.SimpleRenderer;
import net.sourceforge.tess4j.*;
class encoder {
public static byte[] createByteArray(File pCurrentFolder, String pNameOfBinaryFile) {
String pathToBinaryData = pCurrentFolder.getAbsolutePath()+"/"+pNameOfBinaryFile;
File file = new File(pathToBinaryData);
if (!file.exists()) {
System.out.println(pNameOfBinaryFile+" could not be found in folder "+pCurrentFolder.getName());
return null;
}
FileInputStream fin = null;
try {
fin = new FileInputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
byte fileContent[] = new byte[(int) file.length()];
try {
if (fin != null)
fin.read(fileContent);
} catch (IOException e) {
e.printStackTrace();
}
return fileContent;
}
public void covertToImage(File pdfDoc) {
PDFDocument document = new PDFDocument();
try {
document.load(pdfDoc);
} catch (IOException e) {
e.printStackTrace();
}
SimpleRenderer renderer = new SimpleRenderer();
renderer.setResolution(300);
List<Image> images = null;
try {
images = renderer.render(document);
} catch (IOException e) {
e.printStackTrace();
} catch (RendererException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
try {
if (images != null) {
// for testing only 1 page
ImageIO.write((RenderedImage) images.get(10), "png", new File("/home/cloudera/Downloads/1.png"));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class encodeFile {
public static void main(String[] args) {
/* This part is for pure PDF files i.e. not scanned */
//byte[] arr = encoder.createByteArray(new File("/home/cloudera/Downloads/"), "test.pdf");
//String result = javax.xml.bind.DatatypeConverter.printBase64Binary(arr);
//System.out.println(result);
/* This part create the image for a page of scanned PDF file */
new encoder().covertToImage(new File("/home/cloudera/Downloads/isl99201.pdf")); // results in 1.png
/* This part is for OCR */
Tesseract instance = new Tesseract();
String res = instance.doOCR(new File("/home/cloudera/Downloads/1.png"));
System.out.println(res);
}
}
Running this produces these errors:
This occurs when I try to create an image from the PDF. I have seen that if I remove tess4j from build.sbt, image is created with out any errors but I have to use it with that.
Connected to the target VM, address: '127.0.0.1:46698', transport: 'socket'
Exception in thread "main" java.lang.AbstractMethodError: com.sun.jna.Structure.getFieldOrder()Ljava/util/List;
at com.sun.jna.Structure.fieldOrder(Structure.java:884)
at com.sun.jna.Structure.getFields(Structure.java:910)
at com.sun.jna.Structure.deriveLayout(Structure.java:1058)
at com.sun.jna.Structure.calculateSize(Structure.java:982)
at com.sun.jna.Structure.calculateSize(Structure.java:949)
at com.sun.jna.Structure.allocateMemory(Structure.java:375)
at com.sun.jna.Structure.<init>(Structure.java:184)
at com.sun.jna.Structure.<init>(Structure.java:172)
at com.sun.jna.Structure.<init>(Structure.java:159)
at com.sun.jna.Structure.<init>(Structure.java:151)
at org.ghost4j.GhostscriptLibrary$display_callback_s.<init>(GhostscriptLibrary.java:63)
at org.ghost4j.Ghostscript.buildNativeDisplayCallback(Ghostscript.java:381)
at org.ghost4j.Ghostscript.initialize(Ghostscript.java:336)
at org.ghost4j.renderer.SimpleRenderer.run(SimpleRenderer.java:105)
at org.ghost4j.renderer.AbstractRemoteRenderer.render(AbstractRemoteRenderer.java:86)
at org.ghost4j.renderer.AbstractRemoteRenderer.render(AbstractRemoteRenderer.java:70)
at helpers.encoder.covertToImage(encodeFile.java:62)
at helpers.encodeFile.main(encodeFile.java:86)
Disconnected from the target VM, address: '127.0.0.1:46698', transport: 'socket'
Process finished with exit code 1
This error occurs while passing any image to tess4j:
Connected to the target VM, address: '127.0.0.1:46133', transport: 'socket'
Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'tesseract': Native library (linux-x86-64/libtesseract.so) not found in resource path (....)
at com.sun.jna.NativeLibrary.loadLibrary(NativeLibrary.java:271)
at com.sun.jna.NativeLibrary.getInstance(NativeLibrary.java:398)
at com.sun.jna.Library$Handler.<init>(Library.java:147)
at com.sun.jna.Native.loadLibrary(Native.java:412)
at com.sun.jna.Native.loadLibrary(Native.java:391)
at net.sourceforge.tess4j.util.LoadLibs.getTessAPIInstance(LoadLibs.java:78)
at net.sourceforge.tess4j.TessAPI.<clinit>(TessAPI.java:40)
at net.sourceforge.tess4j.Tesseract.init(Tesseract.java:360)
at net.sourceforge.tess4j.Tesseract.doOCR(Tesseract.java:273)
at net.sourceforge.tess4j.Tesseract.doOCR(Tesseract.java:205)
at net.sourceforge.tess4j.Tesseract.doOCR(Tesseract.java:189)
at helpers.encodeFile.main(encodeFile.java:89)
Disconnected from the target VM, address: '127.0.0.1:46133', transport: 'socket'
Process finished with exit code 1
I am working on Intellij using SBT on 64 bit CentOS 6.6. By some internet search I have able to understand the issues above but I am facing two constraints:
The JNA library that is being used is by default of the latest version i.e. 4.1.0. I read on the internet about the incompatibility between JNA and other libraries this can occur. So I tried to specify the older version of 3.4.0. But build.sbt keeps rejecting that.
I am on a 64 Bit system and tessearct would work with a 32 Bit system. How should I integrate it in the project?
Following is the part from build.sbt which handles all the required libraries:
"org.ghost4j" % "ghost4j" % "0.5.1",
"org.bouncycastle" % "bctsp-jdk14" % "1.46",
"net.sourceforge.tess4j" % "tess4j" % "2.0.0",
"com.github.jai-imageio" % "jai-imageio-core" % "1.3.0"
"net.java.dev.jna" % "jna" % "3.4.0", // does not make any difference as only 4.1.0 is installed.
Please help me out in this problem.
UPDATE: I added "net.java.dev.jna" % "jna" % "3.4.0" force() to build.sbt and it solved my first problem.
The solution to this issue lies in the Tesseract-API that I found on github. I forked it into my Github account and added a test for a scanned image and did some code refactoring. This way to library started to function properly. The scanned doc I used for testing is here.
I built it successfully on Travis and now it working fine on 32 as well as 64 bit systems.
I am making a screen recording application with Xuggler. I've basically encapsulated Java Code Geeks' Xuggler tutorial code into a runnable class for the actual recording. It should run just like the tutorial, but I'm getting some (actually a ton of) errors. The link to that code is here: JavaCodeGeeks. I'm not trying to take credit for this entire block of code.
Here is what I have so far:
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.concurrent.TimeUnit;
import javax.swing.JOptionPane;
import src.dtf.gui.GUI;
import com.xuggle.mediatool.IMediaWriter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.xuggler.ICodec;
public class ScreenRecorder implements Runnable {
//Booleans to run and to pause. (Pausing not implemented yet)
boolean running = true;
boolean paused = false;
//Some variables
private GUI gui;
private Toolkit tk;
private String path, name, outputFilename;
private int fps;
private long startTime;
private Rectangle recArea;
private Dimension bounds;
//Declare the MediaWriter
private IMediaWriter writer;
//Constructor
public ScreenRecorder(GUI gui) {
//Set the GUI to the one that I'm using (Another class
this.gui = gui;
//Initialize variables, based on previous user input.
tk = Toolkit.getDefaultToolkit();
path = gui.getPath();
name = JOptionPane.showInputDialog("Please enter a name for your video file:");
outputFilename = path + "\\" + name + ".mp4";
fps = gui.getFPS();
if (gui.fullscreenChecked()) {
recArea = new Rectangle(0, 0, tk.getScreenSize().width,
tk.getScreenSize().height);
} else {
recArea = gui.getArea();
}
bounds = new Dimension(recArea.width, recArea.height);
}
//Start method
public void start() {
gui.disableButtons();
gui.changeRecordButton(false);
running = true;
}
//Run method
public void run() {
//Initialize
init();
long lastTime = System.currentTimeMillis();
int updateTime = 1000 / fps;
startTime = System.nanoTime();
while (running) {
//Limit updates
if (System.currentTimeMillis() - lastTime >= updateTime) {
//Ensure the recording is not paused
if (!paused) {
//If the user has stopped, stop
if (!gui.isRecording()) {
stop();
}
//Take a screenshot and convert it
BufferedImage frame = takeScreenshot();
BufferedImage bgrScreen = convertImage(frame, BufferedImage.TYPE_3BYTE_BGR);
//Encode video
writer.encodeVideo(0, bgrScreen, System.nanoTime() - startTime, TimeUnit.NANOSECONDS);
System.out.println("Recording...");
} else if (paused) {
System.out.println("Paused...");
}
}
}
}
private void init() {
//Make sure the given directory exists
checkFile();
//Ensure there is not already a file of the same name
checkFilename();
//Make the writer
writer = ToolFactory.makeWriter(outputFilename);
writer.addVideoStream(0, 0, ICodec.ID.CODEC_ID_MPEG4, bounds.width, bounds.height);
}
//Method for checking if the directory exists
private void checkFile() {
if (!(new File(path).exists())) {
gui.resetPath();
JOptionPane.showMessageDialog(gui, "ERROR: File path does not exist!");
System.out.println("ERRR");
stop();
}
}
//Method for checking if the given filename exists
private void checkFilename() {
if (new File(path + "\\" + name + ".mp4").exists()) {
JOptionPane.showMessageDialog(gui, "ERROR: File already exists!!");
stop();
}
}
//Method for converting the BufferedImage (Thanks JavaCodeGeeks)
private BufferedImage convertImage(BufferedImage b, int targetType) {
BufferedImage image;
if (b.getType() == targetType) {
image = b;
} else {
image = new BufferedImage(b.getWidth(), b.getHeight(), targetType);
image.getGraphics().drawImage(b, 0, 0, null);
}
return image;
}
//Method for taking a screenshot
private BufferedImage takeScreenshot() {
try {
Robot r = new Robot();
return r.createScreenCapture(recArea);
} catch (AWTException e) {
e.printStackTrace();
return null;
}
}
//Stop method
public void stop() {
gui.enableButtons();
gui.changeRecordButton(true);
//Make sure the writer has been initialized. (Not an incorrect filename or anything)
if (writer != null) {
//Close the writer
writer.close();
}
//End thread
running = false;
}
}
And here's the error that's thrown:
17:46:48.076 [Thread-2] ERROR org.ffmpeg - [mp4 # 000000000028F660] no streams
17:46:48.123 [Thread-2] ERROR com.xuggle.xuggler - Error: could not write header for container (../../../../../../../csrc/com/xuggle/xuggler/Container.cpp:827)
I tried to fix it by adding the isHeaderWritten() if statement in the stop method, but that never gets called at all, so it must be somewhere else (or within that if statement). I don't know what line of my code throws the error, because it only gives me these two errors, which point to Xuggler, not my code. When I execute this, it creates an mp4 file but its size is 0 bytes and the file won't play. I could really use some help because I have no idea what these errors even mean, so it's hard to debug them. Thanks!
We're probably going to get in trouble for not honoring the Q&A-format of this website, so I'm just going to list some things you can try.
The error you are getting regarding the header is also raised when you don't specifically call writeHeader(). You are also getting an error concerning a 'missing stream'. This suggests that Xuggler is missing some information it needs to properly add the video stream and open the writer. So start by debugging your Java application to figure out which specific line is causing the error.
Also, try rendering each output frame to a JFrame, just before you write it. This will allow you to verify whether the BufferedImages you want to write have the proper content.
The file you write to is an MP4, which will make Xuggler draw a couple of conclusions on desired output parameters, but you best not rely on that. Try setting the pixel format, bitrate, frame rate and time base yourself. This is why suggested you use a buffer: you would be able to write frames at a specific interval, which will guarantee the proper frame rate. The way you've set it up now will result in a variable frame rate, which some codecs and containers will not appreciate. The type of buffer isn't that relevant, you could even use an ArrayList. But naturally some data structures will be more efficient than others.
Some codecs and file containers are a lot more forgiving than others. So try out some other codecs as well, such as H.264. You could try changing the file container as well, but MP4 usually works fine in Xuggler.
This is unrelated to your current problem, because this has nothing to do with the output file being empty. But you should watch out for the timestamps with which you write frames. The first video frame should be at timestamp 0, but because you capture and encode in the same while-loop, the first frame will have a much higher timestamp. Also, when you pause, your application won't write any frame but the timestamp will still increase. This will cause a 'hole' in your video when you later resume recording, a small time window without any video data.
I want to get a frame sample (jpeg) from a video file (mov) with java. Is there an easy way to do this. When I search in google all I can find is to make mov from multiple jpgs. I dont know maybe I cannot find the right keywords.
I know that the original question is solved, nevertheless, I am posting this answer in case anyone else got stuck like I did.
Since yesterday, I have tried everything, and I mean everything to do this. All available Java libraries are either out of date, not maintained anymore or lack any kind of usable documentation (seriously??!?!)
I tried JFM (old and useless), JCodec (no documentation whatsoever), JJMpeg (looks promising but is very difficult and cumbersome to use due to lack of Java-class documentation), OpenCV auto-Java builds and a few bunch of other libraries that I cannot remember.
Finally, I decided to take a look at JavaCV's (Github link) classes and voila! It contains FFMPEG bindings with detailed documentations.
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.0</version>
</dependency>
Turns out there is a very easy way to extract video frames from a video file to a BufferedImage and by extension a JPEG file. The class FFmpegFrameGrabber could be easily used for grabbing individual frames and converting them to BufferedImage. A code sample is as follows:
FFmpegFrameGrabber g = new FFmpegFrameGrabber("textures/video/anim.mp4");
g.start();
Java2DFrameConverter converter = new Java2DFrameConverter();
for (int i = 0 ; i < 50 ; i++) {
Frame frame = g.grabImage(); // It is important to use grabImage() to get a frame that can be turned into a BufferedImage
BufferedImage bi = converter.convert(frame);
ImageIO.write(bi, "png", new File("frame-dump/video-frame-" + System.currentTimeMillis() + ".png"));
}
g.stop();
Basically, this code dumps the first 50 frames of the video and saves them as a PNG file. The good thing is that the internal seek function, works on actual frames not keyframes (a problem that I had with JCodec)
You can refer to the JavaCV's homepage to find out more about other classes that can be used for capturing frames from WebCams etc. Hope this answer helps :-)
Xuggler does the job. They even give a sample code which does exactly what I need. Link is below
http://xuggle.googlecode.com/svn/trunk/java/xuggle-xuggler/src/com/xuggle/mediatool/demos/DecodeAndCaptureFrames.java
And I've modified the code in this link such that it saves only the first frame of the video.
import javax.imageio.ImageIO;
import java.io.File;
import java.awt.image.BufferedImage;
import com.xuggle.mediatool.IMediaReader;
import com.xuggle.mediatool.MediaListenerAdapter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.mediatool.event.IVideoPictureEvent;
import com.xuggle.xuggler.Global;
/**
* * #author aclarke
* #author trebor
*/
public class DecodeAndCaptureFrames extends MediaListenerAdapter
{
private int mVideoStreamIndex = -1;
private boolean gotFirst = false;
private String saveFile;
private Exception e;
/** Construct a DecodeAndCaptureFrames which reads and captures
* frames from a video file.
*
* #param filename the name of the media file to read
*/
public DecodeAndCaptureFrames(String videoFile, String saveFile)throws Exception
{
// create a media reader for processing video
this.saveFile = saveFile;
this.e = null;
IMediaReader reader = ToolFactory.makeReader(videoFile);
// stipulate that we want BufferedImages created in BGR 24bit color space
reader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);
// note that DecodeAndCaptureFrames is derived from
// MediaReader.ListenerAdapter and thus may be added as a listener
// to the MediaReader. DecodeAndCaptureFrames implements
// onVideoPicture().
reader.addListener(this);
// read out the contents of the media file, note that nothing else
// happens here. action happens in the onVideoPicture() method
// which is called when complete video pictures are extracted from
// the media source
while (reader.readPacket() == null && !gotFirst);
if (e != null)
throw e;
}
/**
* Called after a video frame has been decoded from a media stream.
* Optionally a BufferedImage version of the frame may be passed
* if the calling {#link IMediaReader} instance was configured to
* create BufferedImages.
*
* This method blocks, so return quickly.
*/
public void onVideoPicture(IVideoPictureEvent event)
{
try
{
// if the stream index does not match the selected stream index,
// then have a closer look
if (event.getStreamIndex() != mVideoStreamIndex)
{
// if the selected video stream id is not yet set, go ahead an
// select this lucky video stream
if (-1 == mVideoStreamIndex)
mVideoStreamIndex = event.getStreamIndex();
// otherwise return, no need to show frames from this video stream
else
return;
}
ImageIO.write(event.getImage(), "jpg", new File(saveFile));
gotFirst = true;
}
catch (Exception e)
{
this.e = e;
}
}
}
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import org.bytedeco.javacpp.opencv_core.IplImage;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FrameGrabber.Exception;
public class Read{
public static void main(String []args) throws IOException, Exception
{
FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber("C:/Users/Digilog/Downloads/Test.mp4");
frameGrabber.start();
IplImage i;
try {
i = frameGrabber.grab();
BufferedImage bi = i.getBufferedImage();
ImageIO.write(bi,"png", new File("D:/Img.png"));
frameGrabber.stop();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Here's how with BoofCV:
String fileName = UtilIO.pathExample("tracking/chipmunk.mjpeg");
MediaManager media = DefaultMediaManager.INSTANCE;
ConfigBackgroundBasic configBasic = new ConfigBackgroundBasic(30, 0.005f);
ImageType imageType = ImageType.single(GrayF32.class);
BackgroundModelMoving background = FactoryBackgroundModel.movingBasic(configBasic, new PointTransformHomography_F32(), imageType);
SimpleImageSequence video = media.openVideo(fileName, background.getImageType());
ImageBase nextFrame;
while(video.hasNext()) {
nextFrame = video.next();
// Now do something with it...
}
maybe this will help you:
Buffer buf = frameGrabber.grabFrame();
// Convert frame to an buffered image so it can be processed and saved
Image img = (new BufferToImage((VideoFormat) buf.getFormat()).createImage(buf));
buffImg = new BufferedImage(img.getWidth(this), img.getHeight(this), BufferedImage.TYPE_INT_RGB);
//TODO saving the buffImg
for more informations:
How to take single snapshots from a webcam?
Below it is shown the essential code to request frames from media files.
For the complete source code and video demo:
"Media File Processing" example using Marvin Framework..
public class MediaFileExample implements Runnable{
private MarvinVideoInterface videoAdapter;
private MarvinImage videoFrame;
public MediaFileExample(){
try{
// Create the VideoAdapter used to load the video file
videoAdapter = new MarvinJavaCVAdapter();
videoAdapter.loadResource("./res/snooker.wmv");
// Start the thread for requesting the video frames
new Thread(this).start();
}
catch(MarvinVideoInterfaceException e){e.printStackTrace();}
}
#Override
public void run() {
try{
while(true){
// Request a video frame
videoFrame = videoAdapter.getFrame();
}
}catch(MarvinVideoInterfaceException e){e.printStackTrace();}
}
public static void main(String[] args) {
MediaFileExample m = new MediaFileExample();
}
}
I know this is a repeat question.
check original one here or here.
So my code is just the copy paste :
import javafx.scene.media.*;
class Gui {
public static void main(String[] args) {
try{
Media hit = new Media("skin.mp3");
MediaPlayer mediaPlayer = new MediaPlayer(hit);
mediaPlayer.play();
}catch(Exception e){
e.printStackTrace();
}
}
}
The exception which i'm getting is :
java.lang.IllegalArgumentException: uri.getScheme() == null!
at com.sun.media.jfxmedia.locator.Locator.<init>(Locator.java:217)
at javafx.scene.media.Media.<init>(Media.java:364)
at Gui.main(gui.java:6)
I'm compiling & running it correctly i.e. by including the jfxrt.jar file in classpath
Note: I'm just using notepad instead of any IDE.
So can anyone tell me the reason of IllegalArgumentException
Thankx
UPDATE : By using file://e:/skin.mp3 it worked fine but left me with another exception :
MediaException: MEDIA_INACCESSIBLE : e
at javafx.scene.media.Media.<init>(Unknown Source)
at Gui.main(gui.java:6)
So if you can put some light on this exception.
By the way i've checked the song, its not corrupt because it is playing nicely in vlc.
From the JavaFX API docs
The supplied URI must conform to RFC-2396 as required by java.net.URI.
Only HTTP, FILE, and JAR URIs are supported.
So, I suspect from reading the docs, you need to supply a URI path.
Something like file://path/to/file/skin.mp3 will probably work.
There are a few problems with the code in this question.
The class needs to be public.
JavaFX 2 applications need to extend the Application class.
JavaFX 2 applications should define a start method.
The locator for the media being created should be a full URI as noted by MadProgrammer.
Even though the question has a javafx-2 tag, I wonder if it is written for JavaFX 1.x JavaFX Script (which is now an unsupported programming language and incompatible with JavaFX 2). If so, I'd recommend coding in Java and using JavaFX 2.x for this rather than JavaFX Script.
On Windows a file representation of an absolute locator of a URI has three slashes after the file protocol. For example, the following is valid:
file:///C:/Users/Public/Music/skin.mp3
For some reason, a single slash will also work (I guess internally Java will interpolate the extra // for the protocol specifier on files or perhaps there is something I don't understand in the URL specification which means that you don't need a // after the protocol).
file:/C:/Users/Public/Music/skin.mp3
One way to check the file uri for something is valid to ask if the file uri exists
System.out.println("File " + filename + " exists? " + new File(filename).exists());
After you know your file uri is valid, you can convert it to a string using.
file.toURI().toURL().toExternalForm()
Here is a short sample program for playing some audio in JavaFX using a MediaPlayer with a little bit of error handling, so that it is easier to understand if something goes wrong.
import java.io.File;
import java.net.MalformedURLException;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.media.*;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/** plays an audio in JavaFX 2.x */
public class SimpleAudioPlayer extends Application {
public static void main(String[] args) { launch(args); }
#Override public void start(Stage stage) throws MalformedURLException {
final Label status = new Label("Init");
MediaPlayer mediaPlayer = createMediaPlayer(
"C:/Users/Public/Music/Sample Music/Future Islands - Before the Bridge.mp3",
status
);
StackPane layout = new StackPane();
layout.getChildren().addAll(status);
stage.setScene(new Scene(layout, 600, 100, Color.CORNSILK));
stage.show();
if (mediaPlayer != null) {
mediaPlayer.play();
}
}
/**
* creates a media player using a file from the given filename path
* and tracks the status of playing the file via the status label
*/
private MediaPlayer createMediaPlayer(final String filename, final Label status) throws MalformedURLException {
File file = new File(filename);
if (!file.exists()) {
status.setText("File does not exist: " + filename);
}
final String mediaLocation = file.toURI().toURL().toExternalForm();
Media media = new Media(mediaLocation);
MediaPlayer mediaPlayer = new MediaPlayer(media);
mediaPlayer.setOnError(new Runnable() {
#Override public void run() {
status.setText("Error");
}
});
mediaPlayer.setOnPlaying(new Runnable() {
#Override public void run() {
status.setText("Playing: " + mediaLocation);
}
});
mediaPlayer.setOnEndOfMedia(new Runnable() {
#Override public void run() {
status.setText("Done");
}
});
return mediaPlayer;
}
}
Here is a link to an additional example of a JavaFX 2.x media player which plays all of the mp3 files in a given directory sequentially.
I am trying to play a video file using JMF but it gives me No Media Player found exception.
Here is my code, can anyone tell me what I am doing wrong here?
public class MediaPanel extends JPanel {
public MediaPanel(URL mediaURL) {
setLayout(new BorderLayout());
try {
Manager.setHint(Manager.LIGHTWEIGHT_RENDERER, true);
Player mediaPlayer = Manager.createRealizedPlayer(mediaURL);
Component video = mediaPlayer.getVisualComponent();
Component controls = mediaPlayer.getControlPanelComponent();
if (video != null)
add(video, BorderLayout.CENTER);
if (controls != null)
add(controls, BorderLayout.SOUTH);
mediaPlayer.start();
} catch (NoPlayerException noPlayerException) {
System.err.println("No media player found");
} // end catch
catch (CannotRealizeException cannotRealizeException) {
System.err.println("Could not realize media player");
} // end catch
catch (IOException iOException) {
System.err.println("Error reading from the source");
}
}
}
public class MediaTest {
public static void main(String args[]) {
// create a file chooser
JFileChooser fileChooser = new JFileChooser();
// show open file dialog
int result = fileChooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION) // user chose a file
{
URL mediaURL = null;
Player mediaPlayer = null;
try {
// get the file as URL
mediaURL = fileChooser.getSelectedFile().toURL();
} catch (MalformedURLException malformedURLException) {
System.err.println("Could not create URL for the file");
}
if (mediaURL != null) {
JFrame mediaTest = new JFrame("Media Tester");
mediaTest.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MediaPanel mediaPanel = new MediaPanel(mediaURL);
mediaTest.add(mediaPanel);
mediaTest.setSize(300, 300);
mediaTest.setVisible(true);
}
}
}
}
The exception that I am getting is No media player found
What kind of video are you trying to play? JMF is a pretty old library and won't be able to play most of modern video formats, only a few old ones (i am not even sure which ones).
Actually, if I am right, to play something specific you will have to write/add your own video-encoders into JMF or at least download and use existing ones, which are usually outdated.
If you really want to have something like tunable video player that could play any modern video there are two options (in my opinion):
Use vlcj library to embed VLC video player into your Java-application
USe JavaFX media player
I am offering only those two because I have dig through tons of libraries some time ago and there were nothing else even close to these two. Plus most of other libraries are outdated as well as JMF itself and these two are getting frequent updates and are supported with lots of users so those two are the best choice.
In case you don't mind embedding Java FX player into your application - that might be your choice.
On the other hand - vlcj is stable and easily integrated into Swing applications (its not like its hard with Java FX, but vlcj might be better for some cases).
Anyway, it is your call what to choose.