getMarkers() {
return markers;
}
/**
* Constructs a Media
instance. This is the only way to
* specify the media source. The source must represent a valid URI
* and is immutable. Only HTTP, HTTPS, FILE, and JAR URL
s are supported. If the
* provided URL is invalid then an exception will be thrown. If an
* asynchronous error occurs, the {@link #errorProperty error} property will be set. Listen
* to this property to be notified of any such errors.
*
* If the source uses a non-blocking protocol such as FILE, then any
* problems which can be detected immediately will cause a MediaException
* to be thrown. Such problems include the media being inaccessible or in an
* unsupported format. If however a potentially blocking protocol such as
* HTTP is used, then the connection will be initialized asynchronously so
* that these sorts of errors will be signaled by setting the {@link #errorProperty error}
* property.
*
* Constraints:
*
* - The supplied URI must conform to RFC-2396 as required by
* java.net.URI.
* - Only HTTP, HTTPS, FILE, and JAR URIs are supported.
*
*
* See java.net.URI
* for more information about URI formatting in general.
* JAR URL syntax is specified in java.net.JarURLConnection.
*
* @param source The URI of the source media.
* @throws NullPointerException if the URI string is null
.
* @throws IllegalArgumentException if the URI string does not conform to RFC-2396
* or, if appropriate, the Jar URL specification, or is in a non-compliant
* form which cannot be modified to a compliant form.
* @throws IllegalArgumentException if the URI string has a null
* scheme.
* @throws UnsupportedOperationException if the protocol specified for the
* source is not supported.
* @throws MediaException if the media source cannot be connected
* (type {@link MediaException.Type#MEDIA_INACCESSIBLE}) or is not supported
* (type {@link MediaException.Type#MEDIA_UNSUPPORTED}).
*/
public Media(@NamedArg("source") String source) {
this.source = source;
URI uri = null;
try {
// URI will throw NPE if source == null: do not catch it!
uri = new URI(source);
} catch(URISyntaxException use) {
throw new IllegalArgumentException(use);
}
metadata = FXCollections.unmodifiableObservableMap(metadataBacking);
tracks = FXCollections.unmodifiableObservableList(tracksBacking);
Locator locator = null;
try {
locator = new com.sun.media.jfxmedia.locator.Locator(uri);
jfxLocator = locator;
if (locator.canBlock()) {
InitLocator locatorInit = new InitLocator();
Thread t = new Thread(locatorInit);
t.setDaemon(true);
t.start();
} else {
locator.init();
runMetadataParser();
}
} catch(URISyntaxException use) {
throw new IllegalArgumentException(use);
} catch(FileNotFoundException fnfe) {
throw new MediaException(MediaException.Type.MEDIA_UNAVAILABLE, fnfe.getMessage());
} catch(IOException ioe) {
throw new MediaException(MediaException.Type.MEDIA_INACCESSIBLE, ioe.getMessage());
} catch(com.sun.media.jfxmedia.MediaException me) {
throw new MediaException(MediaException.Type.MEDIA_UNSUPPORTED, me.getMessage());
}
}
private void runMetadataParser() {
try {
jfxParser = com.sun.media.jfxmedia.MediaManager.getMetadataParser(jfxLocator);
jfxParser.addListener(metadataListener);
jfxParser.startParser();
} catch (Exception e) {
jfxParser = null;
}
}
/**
* The source URI of the media;
*/
private final String source;
/**
* Retrieve the source URI of the media.
* @return the media source URI as a {@link String}.
*/
public String getSource() {
return source;
}
/**
* Locator used by the jfxmedia player, MediaPlayer needs access to this
*/
private final Locator jfxLocator;
Locator retrieveJfxLocator() {
return jfxLocator;
}
private MetadataParser jfxParser;
private Track getTrackWithID(long trackID) {
for (Track track : tracksBacking) {
if (track.getTrackID() == trackID) {
return track;
}
}
return null;
}
// http://javafx-jira.kenai.com/browse/RT-24594
// TODO: Remove this entire method (and associated stuff) when we switch to track parsing in MetadataParser
void _updateMedia(com.sun.media.jfxmedia.Media _media) {
try {
List trackList = _media.getTracks();
if (trackList != null) {
for (com.sun.media.jfxmedia.track.Track trackElement : trackList) {
long trackID = trackElement.getTrackID();
if (getTrackWithID(trackID) == null) {
Track newTrack = null;
Map trackMetadata = new HashMap();
if (null != trackElement.getName()) {
// FIXME: need constants for metadata keys (globally)
trackMetadata.put("name", trackElement.getName());
}
if (null != trackElement.getLocale()) {
trackMetadata.put("locale", trackElement.getLocale());
}
trackMetadata.put("encoding", trackElement.getEncodingType().toString());
trackMetadata.put("enabled", Boolean.valueOf(trackElement.isEnabled()));
if (trackElement instanceof com.sun.media.jfxmedia.track.VideoTrack) {
com.sun.media.jfxmedia.track.VideoTrack vt =
(com.sun.media.jfxmedia.track.VideoTrack) trackElement;
int videoWidth = vt.getFrameSize().getWidth();
int videoHeight = vt.getFrameSize().getHeight();
// FIXME: this isn't valid when there are multiple video tracks...
setWidth(videoWidth);
setHeight(videoHeight);
trackMetadata.put("video width", Integer.valueOf(videoWidth));
trackMetadata.put("video height", Integer.valueOf(videoHeight));
newTrack = new VideoTrack(trackElement.getTrackID(), trackMetadata);
} else if (trackElement instanceof com.sun.media.jfxmedia.track.AudioTrack) {
newTrack = new AudioTrack(trackElement.getTrackID(), trackMetadata);
} else if (trackElement instanceof com.sun.media.jfxmedia.track.SubtitleTrack) {
newTrack = new SubtitleTrack(trackID, trackMetadata);
}
if (null != newTrack) {
tracksBacking.add(newTrack);
}
}
}
}
} catch (Exception e) {
// Save any async exceptions as an error.
setError(new MediaException(MediaException.Type.UNKNOWN, e));
}
}
void _setError(MediaException.Type type, String message) {
setError(new MediaException(type, message));
}
private synchronized void updateMetadata(Map metadata) {
if (metadata != null) {
for (Map.Entry entry : metadata.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (key.equals(MetadataParser.IMAGE_TAG_NAME) && value instanceof byte[]) {
byte[] imageData = (byte[]) value;
Image image = new Image(new ByteArrayInputStream(imageData));
if (!image.isError()) {
metadataBacking.put(MetadataParser.IMAGE_TAG_NAME, image);
}
} else if (key.equals(MetadataParser.DURATION_TAG_NAME) && value instanceof java.lang.Long) {
Duration d = new Duration((Long) value);
if (d != null) {
metadataBacking.put(MetadataParser.DURATION_TAG_NAME, d);
}
} else {
metadataBacking.put(key, value);
}
}
}
}
private class _MetadataListener implements MetadataListener {
@Override
public void onMetadata(final Map metadata) {
// Clean up metadata
Platform.runLater(() -> {
updateMetadata(metadata);
jfxParser.removeListener(metadataListener);
jfxParser.stopParser();
jfxParser = null;
});
}
}
private class InitLocator implements Runnable {
@Override
public void run() {
try {
jfxLocator.init();
runMetadataParser();
} catch (URISyntaxException use) {
_setError(MediaException.Type.OPERATION_UNSUPPORTED, use.getMessage());
} catch (FileNotFoundException fnfe) {
_setError(MediaException.Type.MEDIA_UNAVAILABLE, fnfe.getMessage());
} catch (IOException ioe) {
_setError(MediaException.Type.MEDIA_INACCESSIBLE, ioe.getMessage());
} catch (com.sun.media.jfxmedia.MediaException me) {
_setError(MediaException.Type.MEDIA_UNSUPPORTED, me.getMessage());
} catch (Exception e) {
_setError(MediaException.Type.UNKNOWN, e.getMessage());
}
}
}
}