1 /* 2 * Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.media.jfxmediaimpl.platform.gstreamer; 27 28 import com.sun.media.jfxmedia.Media; 29 import com.sun.media.jfxmedia.MediaError; 30 import com.sun.media.jfxmedia.MediaPlayer; 31 import com.sun.media.jfxmedia.events.PlayerStateEvent.PlayerState; 32 import com.sun.media.jfxmedia.locator.Locator; 33 import com.sun.media.jfxmedia.logging.Logger; 34 import com.sun.media.jfxmediaimpl.HostUtils; 35 import com.sun.media.jfxmediaimpl.MediaUtils; 36 import com.sun.media.jfxmediaimpl.platform.Platform; 37 import java.util.Arrays; 38 39 /** 40 * GStreamer platform implementation. 41 */ 42 public final class GSTPlatform extends Platform { 43 /** 44 * The MIME types of all supported media. 45 */ 46 private static final String[] CONTENT_TYPES = { 47 "audio/x-aiff", 48 "audio/mp3", 49 "audio/mpeg", 50 "audio/x-wav", 51 "video/mp4", 52 "audio/x-m4a", 53 "video/x-m4v", 54 "application/vnd.apple.mpegurl", 55 "audio/mpegurl" 56 }; 57 58 /** 59 * All supported protocols. 60 */ 61 private static final String[] PROTOCOLS = { 62 "file", 63 "http", 64 "https", 65 "jrt" 66 }; 67 68 private static GSTPlatform globalInstance = null; 69 70 @Override 71 public boolean loadPlatform() { 72 // Initialize GStreamer JNI and supporting native classes. 73 MediaError ret; 74 try { 75 ret = MediaError.getFromCode(gstInitPlatform()); 76 } catch (UnsatisfiedLinkError ule) { 77 ret = MediaError.ERROR_MANAGER_ENGINEINIT_FAIL; 78 } 79 // Post an error if native initialization fails. 80 if (ret != MediaError.ERROR_NONE) { 81 MediaUtils.nativeError(GSTPlatform.class, ret); 82 } 83 return true; 84 } 85 86 /* 87 * Get an instance of the platform. 88 */ 89 public static synchronized Platform getPlatformInstance() { 90 if (null == globalInstance) { 91 globalInstance = new GSTPlatform(); 92 } 93 94 return globalInstance; 95 } 96 97 private GSTPlatform() {} 98 99 @Override 100 public String[] getSupportedContentTypes() { 101 return Arrays.copyOf(CONTENT_TYPES, CONTENT_TYPES.length); 102 } 103 104 @Override 105 public String[] getSupportedProtocols() { 106 return Arrays.copyOf(PROTOCOLS, PROTOCOLS.length); 107 } 108 109 @Override 110 public Media createMedia(Locator source) { 111 return new GSTMedia(source); 112 } 113 114 @Override 115 public MediaPlayer createMediaPlayer(Locator source) { 116 GSTMediaPlayer player; 117 try { 118 player = new GSTMediaPlayer(source); 119 } catch (Exception e) { 120 if (Logger.canLog(Logger.DEBUG)) { 121 Logger.logMsg(Logger.DEBUG, "GSTPlatform caught exception while creating media player: "+e); 122 } 123 return null; 124 } 125 126 // Special case for H.264 decoding on Mac OS X. 127 if (HostUtils.isMacOSX()) { 128 String contentType = source.getContentType(); 129 if ("video/mp4".equals(contentType) || "video/x-m4v".equals(contentType) 130 || source.getStringLocation().endsWith(".m3u8")) 131 { 132 // Block until player transitions to READY or HALTED. 133 134 // Timeouts in milliseconds. 135 String scheme = source.getURI().getScheme(); 136 final long timeout = (scheme.equals("http") || scheme.equals("https")) ? 137 60000L : 5000L; 138 final long iterationTime = 50L; 139 long timeWaited = 0L; 140 141 final Object lock = new Object(); 142 PlayerState state = player.getState(); 143 144 while (timeWaited < timeout && 145 (state == PlayerState.UNKNOWN || state == PlayerState.STALLED)) { 146 try { 147 synchronized(lock) { 148 lock.wait(iterationTime); 149 timeWaited += iterationTime; 150 } 151 } catch (InterruptedException ex) { 152 // Ignore it. 153 } 154 155 // Check if error event was set. We will not go to READY or 156 // HALT state in this case. Error event is basically same 157 // as HALT. 158 if (player.isErrorEventCached()) { 159 break; 160 } 161 162 state = player.getState(); 163 } 164 165 // If the player is not READY, an error occurred. 166 if (player.getState() != PlayerState.READY) { 167 player.dispose(); 168 player = null; 169 } 170 } 171 } 172 return player; 173 } 174 175 /** 176 * Initialize the native peer of this media manager. 177 * 178 * @return A status code. 179 */ 180 private static native int gstInitPlatform(); 181 }