Caprica Software

vlcj 3.x Tutorial

Media Information

Building on previous tutorials, we will now show how to get information about the current media.


Let's Get Started

You should now already have a basic template for how to create a vlcj application, so this tutorial will no longer duplicate all of the code each time - instead we'll just show the new code fragments.

There are different kinds of information available:

  • Meta data, like an ID3 tag for MP3 files, things like Title, Genre and so on;
  • Track descriptions, this might be something like a language name for an audio or sub-title track;
  • Chapter descriptions, for a DVD;
  • Track information, this is more detailed information about a track like the codec used, video width and height, audio sample rate and so on.

Some media information is available before you play it so long as you parse it. Parsing media will make meta data available.

Some media information is not available until some indeterminate time after you play it. Even if you play the media and wait for a playing event, the media information might still not be available.

In some cases, specifically with regard to track information, if you query for that information at different times you may get progressively different results

  • i.e. initially you may get basic information which is later refreshed with the gaps filled in.

Parsing Media for Meta Data

Parsing media data makes meta data available, it does not make any track information available.

We first use prepareMedia rather than playMedia to set new media without actually playing (starting) it.

mediaPlayerComponent.getMediaPlayer().prepareMedia(mrl);

After we have prepared media, to parse the current media synchronously:

mediaPlayerComponent.getMediaPlayer().parseMedia();

To parse the current media asynchronously:

mediaPlayerComponent.getMediaPlayer().requestParseMedia();

The asynchronous version will execute in the background and raise a mediaParsedChanged event that you can listen for when the parsing completes.

Care must be taken with the asynchronous approach as an event will not be raised if the media has already been parsed.

You can check if media has been parsed:

mediaPlayerComponent.getMediaPlayer().isMediaParsed();

Parsing media may trigger an HTTP request to fetch meta data and e.g. perform a search for album art. This might be a privacy issue for your application.

There is a new parse method provided with version 3.0.0 and later of VLC that allows you to control whether or not this network request is made, or whether instead the search for meta data should only work locally:

mediaPlayerComponent.getMediaPlayer().requestParseMediaWithOptions(options);

This method also runs asynchronously.

You should consult the Javadoc for more information on the available parse options, if you do not pass any parse options then it is treated as a local parse only and no network request will be made.


Track Descriptions

Track descriptions are the most basic information about the video, audio, sub-title, and title descriptions. These descriptions are typically used as labels in menu items in a user interface. The idea is your user selects the menu item to activate the particular track.

MediaPlayer mediaPlayer = mediaPlayerComponent.getMediaPlayer();
List<TrackDescription> titleTracks = mediaPlayer.getTitleDescriptions();
List<TrackDescription> videoTracks = mediaPlayer.getVideoDescriptions();
List<TrackDescription> audioTracks = mediaPlayer.getAudioDescriptions();
List<TrackDescription> spuTracks = mediaPlayer.getSpuDescriptions();

You get a unique track identifier and a simple textual description, nothing else.

The track identifiers are unique, but there is no guarantee that says they count from zero or that they increase contiguously. You can not assume anything about the track identifiers.

Querying and selecting tracks is straightforward:

MediaPlayer mediaPlayer = mediaPlayerComponent.getMediaPlayer();

int titleCount = mediaPlayer.getTitleCount();
int title = mediaPlayer.getTitle();
mediaPlayer.setTitle(newTitle);

int videoTrackCount = mediaPlayer.getVideoTrackCount();
int videoTrack = mediaPlayer.getVideoTrack();
mediaPlayer.setVideoTrack(newVideoTrack);

int audioTrackCount = mediaPlayer.getAudioTrackCount();
int audioTrack = mediaPlayer.getAudioTrack();
mediaPlayer.setAudioTrack(newAudioTrack);

int spuTrackCount = mediaPlayer.getSpuCount();
int spuTrack = mediaPlayer.getSpuTrack();
mediaPlayer.setSpu(newSpuTrack);

There is usually a 'special' track identifier with an id of -1 and a description of "Disabled". You can use this to disable audio, video or sub-titles if you want.

With VLC 3.0.0+ and vlcj 3.8.0+ you can now query for extended ("full") track information, providing some more attributes:

mediaPlayer.getExtendedTitleDescriptions();

Chapter Descriptions

Chapter descriptions, e.g. for DVD media, are slightly simpler - it is just a list of strings. In pratical terms this is usually no more than "Chapter 1", "Chapter 2" and so on.

Get the chapter descriptions for the current title:

List<String> chapters = mediaPlayerComponent.getMediaPlayer().getChapterDescriptions();

Get the chapter descriptions for all titles (e.g. DVD media might have many 'titles' for the main feature, special features and so on):

List<List<String>> allChapters = mediaPlayerComponent.getMediaPlayer().getAllChapterDescriptions();

You can navigate chapters (chapter numbers count from zero):

MediaPlayer mediaPlayer = mediaPlayerComponent.getMediaPlayer();
int chapterCount = mediaPlayer.getChapterCount();
int currentChapter = mediaPlayer.getChapter();
mediaPlayer.setChapter(newChapter);
mediaPlayer.nextChapter();
mediaPlayer.previousChapter();

With VLC 3.0.0+ and vlcj 3.8.0+ you can now query for extended ("full") chapter information, providing some more attributes:

mediaPlayer.getExtendedChapterDescriptions();
mediaPlayer.getExtendedChapterDescriptions(titleId);

Track Information

Track information contains technical details about the audio, video and sub-title tracks. This is things like the codec, bit-rate, for video tracks it is things like width and height, for audio tracks it is things like sample-rate and so on and so on.

You can query all track information in one call, or you can just query for one or more specific types of track information that you are interested in.

All tracks:

MediaPlayer mediaPlayer = mediaPlayerComponent.getMediaPlayer();
List<TrackInfo> trackInfo = mediaPlayer.getTrackInfo();

Specific track types, here we just pick audio and video:

MediaPlayer mediaPlayer = mediaPlayerComponent.getMediaPlayer();
List<TrackInfo> trackInfo = mediaPlayer.getTrackInfo(TrackType.AUDIO, TrackType.VIDEO);

Note that TrackType.TEXT is used for sub-title tracks.

The track information forms a sub-class hierarchy for the different types available: base-class TrackInfo and sub-classes AudioTrackInfo, VideoTrackInfo and TextTrackInfo.

When you iterate the returned track information list, if you are interested in the attributes from the sub-classes you must cast the track information reference to the appropriate type.

If you requested a particular type:

MediaPlayer mediaPlayer = mediaPlayerComponent.getMediaPlayer();
List<TrackInfo> trackInfo = mediaPlayer.getTrackInfo(TrackType.VIDEO);
for (TrackInfo track : trackInfo) {
VideoTrackInfo videoTrack = (VideoTrackInfo) track;
// ... use videoTrack ...
}

If you requested multiple types:

MediaPlayer mediaPlayer = mediaPlayerComponent.getMediaPlayer();
List<TrackInfo> trackInfo = mediaPlayer.getTrackInfo();
for (TrackInfo track : trackInfo) {
if (track instanceof AudioTrackInfo) {
AudioTrackInfo audioTrack = (AudioTrackInfo) track;
// ... use audioTrack ...
}
else if (track instanceof VideoTrackInfo) {
VideoTrackInfo videoTrack = (VideoTrackInfo) track;
// ... use videoTrack ...
}
else if (track instanceof TextTrackInfo) {
TextTrackInfo textTrack = (TextTrackInfo) track;
// ... use textTrack ...
}
}

Events

With VLC 3.0.0 and later there are new media player events raised when the various tracks are discovered. You could use this e.g. to dynamically build track menus.

As has been explained in another tutorial, you can add a listener or you can override template methods in the media player component. We will use template methods:

mediaPlayerComponent = new EmbeddedMediaPlayerComponent() {
@Override
public void elementaryStreamAdded(MediaPlayer mediaPlayer, int type, int id) {
}

@Override
public void elementaryStreamDeleted(MediaPlayer mediaPlayer, int type, int id) {
}

@Override
public void elementaryStreamSelected(MediaPlayer mediaPlayer, int type, int id) {
}
};

In these event handlers, type comes from libvlc_track_type_t and id is the unique identifier for the track.

For the stream added and stream deleted events you could use this to dynamically create a menu. For the stream selected event you could use these to show which track of a particular type is current - you may for example use a check-box menu item and check the corresponding track.


Media Information Availability

As stated right at the start of this tutorial, the media information is not always immediately available.

If you are building a media player with a user interface, the best strategy really is to query for media information on demand and each time you demand it.

What this means in practice is that if you are building up a menu of tracks then query for the track information just before you are about to show the menu. For this specific case you can add a standard MenuListener to your menu and the menuSelected event will be raised, and this is where you can query the track information.

This same on-demand strategy is a good strategy for all of the media information we've covered in this tutorial.


Summary

This tutorial has shown how to get the available media details, the meta data, the track descriptions, the detailed track information chapter descriptions and so on. We have also described when that information becomes available and a strategy for using the information to build a user interface.