/*
 * Copyright (c) 2010, 2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.media.jfxmediaimpl;

import com.sun.glass.utils.NativeLibLoader;
import com.sun.media.jfxmedia.*;
import com.sun.media.jfxmedia.events.MediaErrorListener;
import com.sun.media.jfxmedia.locator.Locator;
import com.sun.media.jfxmedia.logging.Logger;
import com.sun.media.jfxmediaimpl.platform.PlatformManager;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.WeakHashMap;

A class representing a native media engine.
/** * A class representing a native media engine. */
public class NativeMediaManager {
Whether the native layer has been initialized.
/** * Whether the native layer has been initialized. */
private static boolean isNativeLayerInitialized = false; /** * The {@link MediaErrorListener}s. */ // FIXME: Change to WeakHashMap<MediaErrorListener,Boolean> as it's more efficient private final List<WeakReference<MediaErrorListener>> errorListeners = new ArrayList(); private final static NativeMediaPlayerDisposer playerDisposer = new NativeMediaPlayerDisposer();
List of all un-disposed players.
/** * List of all un-disposed players. */
private final static Map<MediaPlayer,Boolean> allMediaPlayers = new WeakHashMap(); // cached content types, so we don't have to poll and sort each time, this list // should never change once we're initialized private final List<String> supportedContentTypes = new ArrayList(); private final List<String> supportedProtocols = new ArrayList<>();
The NativeMediaManager singleton.
/** * The NativeMediaManager singleton. */
private static class NativeMediaManagerInitializer { private static final NativeMediaManager globalInstance = new NativeMediaManager(); }
Get the default NativeMediaManager.
Returns:the singleton NativeMediaManager instance.
/** * Get the default * <code>NativeMediaManager</code>. * * @return the singleton * <code>NativeMediaManager</code> instance. */
public static NativeMediaManager getDefaultInstance() { return NativeMediaManagerInitializer.globalInstance; } //************************************************************************** //***** Constructors //**************************************************************************
Create a NativeMediaManager.
/** * Create a <code>NativeMediaManager</code>. */
protected NativeMediaManager() { /* * Load native libraries. This must be done early as platforms may need * to attempt loading their own native libs that are dependent on these * This is a slight performance hit, but necessary otherwise we could * erroneously report content types for platforms that cannot be loaded */ try { AccessController.doPrivileged((PrivilegedExceptionAction) () -> { ArrayList<String> dependencies = new ArrayList<>(); if (HostUtils.isWindows() || HostUtils.isMacOSX()) { NativeLibLoader.loadLibrary("glib-lite"); } if (!HostUtils.isLinux() && !HostUtils.isIOS()) { NativeLibLoader.loadLibrary("gstreamer-lite"); } else { dependencies.add("gstreamer-lite"); } if (HostUtils.isLinux()) { dependencies.add("fxplugins"); dependencies.add("avplugin"); dependencies.add("avplugin-54"); dependencies.add("avplugin-56"); dependencies.add("avplugin-57"); dependencies.add("avplugin-ffmpeg-56"); dependencies.add("avplugin-ffmpeg-57"); } if (HostUtils.isMacOSX()) { dependencies.add("fxplugins"); dependencies.add("glib-lite"); dependencies.add("jfxmedia_avf"); } if (HostUtils.isWindows()) { dependencies.add("fxplugins"); dependencies.add("glib-lite"); } NativeLibLoader.loadLibrary("jfxmedia", dependencies); return null; }); } catch (PrivilegedActionException pae) { MediaUtils.error(null, MediaError.ERROR_MANAGER_ENGINEINIT_FAIL.code(), "Unable to load one or more dependent libraries.", pae); } // Get the Logger native side rolling before we load platforms if (!Logger.initNative()) { MediaUtils.error(null, MediaError.ERROR_MANAGER_LOGGER_INIT.code(), "Unable to init logger", null); } }
Initialize the native layer if it has not been so already.
/** * Initialize the native layer if it has not been so already. */
synchronized static void initNativeLayer() { if (!isNativeLayerInitialized) { // load platforms PlatformManager.getManager().loadPlatforms(); // Set the native initialization flag, even if initialization failed. isNativeLayerInitialized = true; } } //************************************************************************** //***** Public control functions //************************************************************************** private synchronized void loadContentTypes() { if (!supportedContentTypes.isEmpty()) { // already populated, just return return; } List<String> npt = PlatformManager.getManager().getSupportedContentTypes(); if (null != npt && !npt.isEmpty()) { supportedContentTypes.addAll(npt); } if (Logger.canLog(Logger.DEBUG)) { StringBuilder sb = new StringBuilder("JFXMedia supported content types:\n"); for (String type : supportedContentTypes) { sb.append(" "); sb.append(type); sb.append("\n"); } Logger.logMsg(Logger.DEBUG, sb.toString()); } } private synchronized void loadProtocols() { if (!supportedProtocols.isEmpty()) { // already populated, just return return; } List<String> npt = PlatformManager.getManager().getSupportedProtocols(); if (null != npt && !npt.isEmpty()) { supportedProtocols.addAll(npt); } if (Logger.canLog(Logger.DEBUG)) { StringBuilder sb = new StringBuilder("JFXMedia supported protocols:\n"); for (String type : supportedProtocols) { sb.append(" "); sb.append(type); sb.append("\n"); } Logger.logMsg(Logger.DEBUG, sb.toString()); } }
Whether a media source having the indicated content type may be played.
Throws:
See Also:
  • canPlayContentType.canPlayContentType(String)
/** * Whether a media source having the indicated content type may be played. * * @see MediaManager#canPlayContentType(java.lang.String) * * @throws IllegalArgumentException if * <code>contentType</code> is * <code>null</code>. */
public boolean canPlayContentType(String contentType) { if (contentType == null) { throw new IllegalArgumentException("contentType == null!"); } if (supportedContentTypes.isEmpty()) { loadContentTypes(); } /* * Don't just use supportedContentType.contains(contentType) as that * is case sensitive, which we do not want */ for (String type : supportedContentTypes) { if (contentType.equalsIgnoreCase(type)) { return true; } } return false; } public String[] getSupportedContentTypes() { if (supportedContentTypes.isEmpty()) { loadContentTypes(); } return supportedContentTypes.toArray(new String[1]); }
Whether a media source having the indicated protocol may be played.
Throws:
See Also:
  • canPlayProtocol.canPlayProtocol(String)
/** * Whether a media source having the indicated protocol may be played. * * @see MediaManager#canPlayProtocol(java.lang.String) * * @throws IllegalArgumentException if * <code>protocol</code> is * <code>null</code>. */
public boolean canPlayProtocol(String protocol) { if (protocol == null) { throw new IllegalArgumentException("protocol == null!"); } if (supportedProtocols.isEmpty()) { loadProtocols(); } /* * Don't just use supportedProtocols.contains(protocol) as that * is case sensitive, which we do not want */ for (String type : supportedProtocols) { if (protocol.equalsIgnoreCase(type)) { return true; } } return false; } public static MetadataParser getMetadataParser(Locator locator) { return PlatformManager.getManager().createMetadataParser(locator); }
See Also:
  • getPlayer.getPlayer(Locator, int)
/** * @see MediaManager#getPlayer(com.sun.media.jfxmedia.locator.Locator, int) */
public MediaPlayer getPlayer(Locator locator) { // FIXME: remove this initNativeLayer(); MediaPlayer player = PlatformManager.getManager().createMediaPlayer(locator); if (null == player) { throw new MediaException("Could not create player!"); } // Cache a reference to the player. allMediaPlayers.put(player, Boolean.TRUE); return player; }
Get a player for the media locator. A preference may be set as to whether to allow a full scan of the media. FIXME: Nuke permitFullScan, it is unused and has no effect
Params:
  • locator –
  • permitFullScan –
Returns:MediaPlayer object
/** * Get a player for the media locator. A preference may be set as to whether * to allow a full scan of the media. * * FIXME: Nuke permitFullScan, it is unused and has no effect * * @param locator * @param permitFullScan * @return MediaPlayer object */
public Media getMedia(Locator locator) { initNativeLayer(); return PlatformManager.getManager().createMedia(locator); }
See Also:
  • addMediaErrorListener.addMediaErrorListener(MediaErrorListener)
/** * @see * MediaManager#addMediaErrorListener(com.sun.media.jfxmedia.events.MediaErrorListener) */
public void addMediaErrorListener(MediaErrorListener listener) { if (listener != null) { // Since we have only one instance of NativeMediaManager, all media players // created during application lifecycle will keep weak references to error // listeners in errorListeners. Lets clean up unused references. // FIXME: change to WeakHashMap<MEL,Boolean> as it's more efficient for (ListIterator<WeakReference<MediaErrorListener>> it = errorListeners.listIterator(); it.hasNext();) { MediaErrorListener l = it.next().get(); if (l == null) { it.remove(); } } this.errorListeners.add(new WeakReference<MediaErrorListener>(listener)); } }
See Also:
  • removeMediaErrorListener.removeMediaErrorListener(MediaErrorListener)
/** * @see * MediaManager#removeMediaErrorListener(com.sun.media.jfxmedia.events.MediaErrorListener) */
public void removeMediaErrorListener(MediaErrorListener listener) { if (listener != null) { // FIXME: change to WeakHashMap<MEL,Boolean> as it's more efficient for (ListIterator<WeakReference<MediaErrorListener>> it = errorListeners.listIterator(); it.hasNext();) { MediaErrorListener l = it.next().get(); if (l == null || l == listener) { it.remove(); } } } }
This function will register MediaPlayer for disposing when obj parameter does not have any strong reference. FIXME: Nuke this and use MediaDisposer instead
Params:
  • obj – - Object to watch for strong references
  • player – - MediaPlayer to dispose
/** * This function will register MediaPlayer for disposing when obj parameter * does not have any strong reference. * * FIXME: Nuke this and use MediaDisposer instead * * @param obj - Object to watch for strong references * @param player - MediaPlayer to dispose */
public static void registerMediaPlayerForDispose(Object obj, MediaPlayer player) { MediaDisposer.addResourceDisposer(obj, player, playerDisposer); }
Retrieve all un-disposed MediaPlayers.
Returns:a List of all un-disposed players or null.
/** * Retrieve all un-disposed {@link MediaPlayer}s. * * @return a {@link List} of all un-disposed players or * <code>null</code>. */
public List<MediaPlayer> getAllMediaPlayers() { List<MediaPlayer> allPlayers = null; if (!allMediaPlayers.isEmpty()) { allPlayers = new ArrayList<MediaPlayer>(allMediaPlayers.keySet()); } return allPlayers; } //************************************************************************** //***** Private functions //************************************************************************** List<WeakReference<MediaErrorListener>> getMediaErrorListeners() { return this.errorListeners; } private static class NativeMediaPlayerDisposer implements MediaDisposer.ResourceDisposer { public void disposeResource(Object resource) { // resource is a MediaPlayer MediaPlayer player = (MediaPlayer) resource; if (player != null) { player.dispose(); } } } }