Currently I am working on some code based on VLCJ to play video content, which is working pretty fine, but I am struggling hard making the setSpu() method work.
Just to mention, when it comes to load an external subtitle, in a file apart from the video file, it is working fine. The problem appears when I try to play subtitles contained in the media file. (e.g. subs contained into a MKV file).
I read carefully GitHub post "setSpu not working #278", and I think that maybe the problem is that I am not invoking the setSpu() method correctly.
To make it simple, I am trying to make it works on the example "uk.co.caprica.vlcj.test.basic.TestPlayer".
On TestPlayer.java class, I loaded all native vlc required libs and configured the mediaPath, and mediaPlayer, so if I execute the class, the media player is built properly, and the video starts playing.
Now, to try make the subtitle work, I reused the button "subTitlesButton" on "PlayerControlsPanel.java". First of all, as the spu to be set is the ID of the TrackDescription, I added the following code, and executed to get the spuDescriptions list:
subTitlesButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(mediaPlayer.getSpuDescriptions());
}
});
When the Sub-titles button is pressed, the following output is get:
spuDescriptions=[TrackDescription[id=-1,description=Deshabilitar], TrackDescription[id=3,description=Pista 1 - [Español]], TrackDescription[id=4,description=Pista 2 - [Inglés]], TrackDescription[id=5,description=Pista 3 - [Español]]]
So, to keep it simple, I just tried to add the following code and execute it:
subTitlesButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(mediaPlayer.getSpuDescriptions());
mediaPlayer.setSpu(3); // TrackDescription[id=3,description=Track 1 - [Spanish]]
}
});
The expected resault would be the subtitle "Track 1 - [Spanish]" with ID=3 to appear on screen, but nothing happens. The video goes on and is being played properly, but the sub-title is not shown.
All the other buttons, work fine when you pressed them, you get the expected result (pause, stop, play, fastforward, rewind, and so on)... so I dont get the point on why media.setSpu() is not working there.
Would be much appreciated some help :)
Thanks in advance.
EDITED The exact problem was that all subtitles contained in the media file (video.mkv) were UTF8 text encoded. I tried to re-mount the video.mkv file with mkvmerge, but this program allways converts SRT files to UTF8 text format.
WORKAROUND convert the SRT files to ASS subtitles format. If the video.mkv contains .ASS subtitles format, the subtitles are always loaded properly by VLC and also by vlcj libs.
Thanks a lot in advance for all the help provided.
If this question can be distilled down to how to use external SPU files with non-ASCII characters, you can try this:
Suppose you have some filename for your external SPU file, the filename containing non-ASCII characters, let's call this spuFileName...
Try:
String asciiFileName = new File(spuFileName)
.toURI()
.toASCIIString();
Or:
String asciiFileName = new File(spuFileName)
.toURI()
.toASCIIString()
.replaceFirst("file:/", "file:///");
Then use asciiFileName instead when you specify the SPU file for vlcj.
If I remember correctly, LibVLC requires ASCII strings on its API. This problem can also show itself if you try and play a video with a filename that contains non-ASCII characters (vlcj detects this and handles it automatically).
But I'm not sure if this really is your problem as given the partial log you posted it looks like VLC has indeed detected the SPU tracks correctly.
On the other hand, if this suggestion does actually work, vlcj could be changed to handle this case (an external SPU file) automatically.
When actually selecting SPU for display, whether the SPU are in a separate file or contained within the video itself, the only thing that matters is the id of the SPU track. vlcj passes this id directly to the LibVLC API method. The fact that the track description strings are not being encoded directly does not matter.
In earlier versions of VLC, this id was actually the index of the SPU track - so 0, 1, 2, 3 and so on.
With the current version of VLC (this was changed around February 2013, I think this means VLC 2.1+) this was fixed to use the actual SPU track identifiers.
So depending on your version of VLC, if the track identifiers are not working for you try just passing an index instead.
Related
Android 11,
I'm trying to create a publicly accessible folder I can store my media files within, which will contain 1 folder and 1 text file per game type (there could be many), I do not want any other application to have access to the root folder for the exception of file explorers, as the user 'could' have content inside the folder that is R18 restricted or might not, I'm not in control of what content goes in there, it would be nice if I could provide that so that a child doesn't in mistakenly bump into the content while looking for pictures on the device for barnie.
I found some code on GitHub that did just the above on Android 10 and works flawlessly for Android 10, but cannot find anything but blue pills about it when it comes to Android 11, help in the form of example code would be great, yes I know targeting only Android 11 limits me but I'd rather live with the limit than play with many different versions of code.
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).apply {
flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
}
startActivityForResult(intent, OPEN_FOLDER_REQUEST_CODE)
EDIT 2
After some hacking around, because 'startActivityForResult(Intent!, Int): Unit' is deprecated. Deprecated in Java, I end up with this, results is a URI, can I now use this to pass files to other API calls now?
pref = getSharedPreferences("myPref", Context.MODE_PRIVATE)
var userFolderData: String? = pref.getString("userFolderData", "")
if (userFolderData=="") {
val getUserFolderData =
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) {
mytools.debug(it.toString())
pref.edit().putString("userFolderData",it.toString()).apply()
userFolderData = it.toString()
}
getUserFolderData.launch("".toUri())
}
mytools.debug("userFolderData = ${userFolderData}")
EDIT 3
So I ran a test on the URI returned; always the same story not matter what I do, yes that's pretty ugly hack but it's the easiest way I can find to test it.
ivtitleimage.setImageURI("content://com.android.externalstorage.documents/document/primary%3ATest%2FMelsDeck%2Fbendover01.jpg".toUri())
31833-31833/com.example.cardgamexxx E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.cardgamexxx, PID: 31833
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.cardgamexxx/com.example.cardgamexxx.MainActivity}: java.lang.SecurityException: Permission Denial: opening provider com.android.externalstorage.ExternalStorageProvider from ProcessRecord{5a390cf 31833:com.example.cardgamexxx/u0a741} (pid=31833, uid=10741) requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs
EDIT 4
Right, so user selects folder/creates one with registerForActivityResult code above, I place files in it with Cx File Explorer and automagically drum roll! ...
I do not have read access to the file placed there, anyway thought I'd comment here as I don't want people stumbling on the post and thinking this works, because it doesn't.
On an Android 11 device your app can only create folders on root of external storage in the classic way if it has requested 'all files acces'.
Or it can use Storage Access Framework and for instance ACTION_OPEN_DOCUMENT_TREE to let the user create a folder in root of external storage and then select it.
I'm trying to create a basic Media Player in JavaFX. I finally made it possible to display the album cover based on the metadata on the file.
However on some songs it doesn't show anything, even if I know that there is an album cover.
Here theres no problem:
However when I select another file it just looks like this:
I swear the only thing I'm changing is the name of the song. Both of the files are formatted in MP3 and have a 500x500 jpg as album cover. The song plays succesfully. Meaning that the file exist. But no album cover
the me variable is the Media which contains the file.
This is the method I'm using to display the album cover in the program:
private void displayAlbumCover (){
// Will start to show a blank CD
File file = new File("src/sample/images/blank_cd.jpeg");
Image image = new Image(file.toURI().toString());
albumCoverView.setImage(image);
// However if an album cover is found in the meta-data it will be displayed
ObservableMap<String,Object> meta_data=me.getMetadata();
meta_data.addListener((MapChangeListener<String, Object>) ch -> {
if(ch.wasAdded()){
String key=ch.getKey();
Object value=ch.getValueAdded();
if (key.equals("image")){
// If there's an album cover in the metadata it will be displayed
albumCoverView.setImage((Image)value);
System.out.println("Found album cover");
}
}
});
}
Okay I've tried debugging, and this is what I get:
The one above is the one that works fine.
But this one does not. Can you see something based on the information, that I gave you?
I've seen how the GMOTE 2.0 runs on Android. The accessing of media files on computer is really cool and making them play makes it much cooler and the other features of it.
Now, I would like to make a program for android and for PC. What I want to make is like the GMOTE 2.0 but i only want the way it plays mp3 files over the PC. And my PC and Android is on the same newtork (same router).
Can someone give me advice on how this will be started and what would I be needing?
Please help me I don't know how will this be started. Is it possible communicating thru ports? (Like TCP?)
It shouldn't be difficult. Basically, you need to create two components:
Remote control driver: This application will be running on the computer. It should be able to do at least these things:
Export list of all songs. It depends on you, how sophisticated it should be. I would
suggest to export all songs from the computer in a XML. It may look like this:
<?xml version="1.0" encoding="UTF-8" ?>
<list>
<artist name="Fear Factory">
<album name="Demanufacture" year="1995">
<song name="Demanufacture" track="01" filename="C:\MyMusic\FearFactory\01. Demanufacture.mp3" />
<song name="Self-bias resistor" track="02" filename="C:\MyMusic\FearFactory\01. Self-bias resistor.mp3" />
</album>
</artist>
<artist name="Sybreed">
<album name="Slave design">
<song name="Bioactive" track="01" filename="C:\MyMusic\Sybreed\bioactive.mp3" />
</album>
</artist>
</list>
To generate such a list, you'll need to define path to some local folder(s). Now you
can go through the whole folder and read name of each file. Then you can use some
library and read ID3 tags (which contains name of the artist etc) from these files.
It should be very easy to generate this list.
Create an network interface, which will be listening on some TCP port and waiting for
commands. If it receive some command, it'll just proceed some action or send response.
You'll probably need these types of commands:
UPDATE_DATABASE: It will create XML as shown above and send it to your mobile
mobile phone.
PLAY_SONG: Receive full filename (as shown in the XML) and start playing of that
song in the background. There exists some libraries which can do this for you.
Example with Slick2D:
new Sound("some_music.wav").play();
It's automatically started in another thread, so you don't have to worry about
that. However, Slick2D is primary for game development, so it would be better to
look for something else.
Another possibility is to just start some media player (or console media player).
But I wouldn't recommend that as it will be much more difficult to control
whether the song is playing or not, or to pause it.
PAUSE_SONG
GET_CURRENT_SONG: It'll just look for the name of currently playing song and send
it back.
This application doesn't have to be graphical (but it'd be nice). The simplest and ugliest
version might be something like this:
public static void main(String args[]) {
TCPServer server = new TCPServer(999);
Sound sound = null;
for (;;) {
String command = server.accept();
if (command.equals("UPDATE_DATABASE)) {
// generate xml
server.sendData(xml.getRawContent());
} else if (command.equals("PLAY_SONG")) {
String filename = server.accept();
sound = new Sound(filename);
sound.play();
} else if (command.equals("PAUSE_SONG")) {
if (sound.playing()) {
sound.pause();
} else {
sound.play();
}
}
}
}
Most of classes I've used probably doesn't exist. Remember, that this is just a very
simplified example.
Application for mobile phone. And that's up to you. You'll need to create a
network client, which will be able to communicate with computer. It's simplest as it can be.
You'll just send something like "UPDATE_DATABASE" and receive some data as XML. Then
you'll use some library (probably DOM parser) and show list of songs to the user (it
may be also sorted into categories).
When user click to some song, it'll read it's filename (see that attribute in XML above).
And what's more easy than just send something like: "PLAY_SONG C:\MyMusic...."? Well,
maybe one thing - pausing the song. You'll maybe figure out by yourself how to do that.
:-)
That should be all. I hope I haven't forgotten something important.
From within Java, I am opening an Excel file with the default file handler (MS Excel, in this case :-) ) using the method described in this stackoverflow question:
Desktop dt = Desktop.getDesktop();
dt.open(new File(filename));
However, the Excel program doesn't get the focus. Is there any easy way to do so?
Edit: There is a related stackoverflow question for C#, but I didn't find any similar Java method.
Edit 2: I've did some simple tests, and discovered that Excel starts and gets the focus whenever no instance of Excel is running. When Excel is already open en NOT minimized, the application doesn't get the focus. If instead the Excel Windows was minimized, the above code will trigger a maximization of the window and Excel getting the focus (or vice versa :-) ).
If you only care about Windows (implied in the question), you can change the way you invoke Excel: use "cmd start...".
I have been using this piece of code to launch Windows applications for some time now. Works every time. It relies on the file association in Windows to find the application. The launched application becomes the focused window on the desktop.
In your case, Excel should be associated with .xls, .csv and other typical extensions. If it is, Windows will launch Excel, passing your file to it.
Usage:
MyUtilClass.startApplication( "c:\\mydir\\myfile.csv", "my window title" );
file is the full path to the input file for Excel and title is the window title (the application may or may not take it - Excel changes the window title).
public static void startApplication( String file, String title )
{
try
{
Runtime.getRuntime().exec( new String[] { "cmd", "/c", "start", title, file } );
}
catch( Exception e )
{
System.out.println( e.getMessage() );
}
}
From a scala-program, which runs in the JVM too, I can open an application, and that get's the focus by default. (Tested with xUbuntu, which is a kind of Linux).
import java.awt.Desktop
val dt = Desktop.getDesktop ();
dt.open (new java.io.File ("euler166.svg"));
I can't say, whether this is specific for Linux, or maybe something else - however starting Inkscape in my example, excel in yours, may take a few seconds, while the user impatiently clicks in the javaprogram again, thereby claiming the cursor back. Did you check for that?
You could then change to the last application, at least on Linux and Windows with ALT-Tab aka Meta-Tab (again shown in scala code, which you can easily transform to javacode, I'm sure):
import java.awt.Robot
import java.awt.event._
val rob = new Robot ()
rob.keyPress (KeyEvent.VK_META)
rob.keyPress (KeyEvent.VK_TAB)
rob.keyRelease (KeyEvent.VK_TAB)
rob.keyRelease (KeyEvent.VK_META)
but unfortunately the unknown source off more trouble, also known as user, might do nothing, so switching would be the false thing to do. Maybe with a thread, which checks for a certain amount of time, whether the java-program has the focus, but it keeps a form of roulette, in an interactional environment, because the user may have a fast or slow machine, or change to a third application meanwhile, and so on. Maybe a hint before triggering the new app is the best you can do?
I'm experimenting with JavaFX making a small game.
I want to add sound.
How?
I tried MediaPlayer with media defined with relative source attribute like:
attribute media = Media{
source: "{__FILE__}/sound/hormpipe.mp3"
}
attribute player = MediaPlayer{
autoPlay:true
media:media
}
It doesn't play.
I get
FX Media Object caught Exception com.sun.media.jmc.MediaUnavailableException: Media unavailable: file: ... Sound.class/sound/hormpipe.mp3
Just a guess, but is that file "hornpipe.mp3" and not "hormpipe.mp3" (with an m)?
var player = javafx.scene.media.MediaPlayer {
repeatCount: javafx.scene.media.MediaPlayer.REPEAT_FOREVER
media: Media { source: "{\_\_DIR\_\_}clip.wav"
};
};
player.play();
You have to incluye the audio file in the build/compiled directory so Netbeans can pack it into the jar file.
Just a guess, but I think your {__FILE__} will expand to the name of your file. Try replacing it with {__DIR__}.
Also note that {__DIR__} includes the trailing /, so try this instead:
attribute media = Media{
source: "{__DIR__}sound/hormpipe.mp3"}
EDIT: I did some digging, and apparently, the source of a Media object has to be either a remote URL, or an absolute file path, since media files aren't allowed in JARs (something I hope gets changed with future releases, since I really like JavaFX and want to be able to make desktop apps with it). See: JavaFX FAQs.
This worked for me:
MediaPlayer audio = new MediaPlayer(
new Media(
new File("file.mp3").toURI().toString()));
Source file should be in project's root directory (not src, not dist).
OK, having used this question to get MP3 audio working (kinda), I've learned the following (not much).
1) Audio for compressed formats is very platform dependent. My continually upgraded Mint 17.1->18 machine plays mp3 fine using Media and MediaPlayer. Fresh installs of Mint 18 won't (with the dev tools).
So use .wav files.
Media sound=new Media(new File("noises/roll.wav").toURI().toString());
MediaPlayer mediaPlayer=new MediaPlayer(sound);
mediaPlayer.play();
2) One of the things you need to be aware of with Media/MediaPlayer is that in order to play multiple times (repeatedly or all at once ie, on a button press/whatever in a game) you have to spawn N number of MediaPlayer objects, and each one will play once and then stop.
So use javafx.scene.media.AudioClip
AudioClip soundMyNoise = new AudioClip(new File("noises/roll.wav").toURI().toString());
soundMyNoise.play();
AudioClip also has its issues, which include storing the raw audio data in RAM all at once instead of buffering. So there is the possibility of excessive memory use.
No matter which method you end up going with, one thing to be critically aware of was mentioned by daevon earlier - the path issue. With NetBeans, you have NetBeansProjects/yourproject/src/yourproject/foo.java. The sounds in the example above go in NetBeansProjects/yourproject/noises/roll.wav