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 }; 66 67 private static GSTPlatform globalInstance = null; 68 69 @Override 70 public boolean loadPlatform() { 71 // Initialize GStreamer JNI and supporting native classes. 72 MediaError ret; 73 try { 74 ret = MediaError.getFromCode(gstInitPlatform()); 75 } catch (UnsatisfiedLinkError ule) { 76 ret = MediaError.ERROR_MANAGER_ENGINEINIT_FAIL; 77 } 78 // Post an error if native initialization fails. 79 if (ret != MediaError.ERROR_NONE) { 80 MediaUtils.nativeError(GSTPlatform.class, ret); 81 } 82 return true; 83 } 84 85 /* 86 * Get an instance of the platform. 87 */ 88 public static synchronized Platform getPlatformInstance() { 89 if (null == globalInstance) { 90 globalInstance = new GSTPlatform(); 91 } 92 93 return globalInstance; 94 } 95 96 private GSTPlatform() {} 97 98 @Override 99 public String[] getSupportedContentTypes() { 100 return Arrays.copyOf(CONTENT_TYPES, CONTENT_TYPES.length); 101 } 102 103 @Override 104 public String[] getSupportedProtocols() { 105 return Arrays.copyOf(PROTOCOLS, PROTOCOLS.length); 106 } 107 108 @Override 109 public Media createMedia(Locator source) { 110 return new GSTMedia(source); 111 } 112 113 @Override 114 public MediaPlayer createMediaPlayer(Locator source) { 115 GSTMediaPlayer player; 116 try { 117 player = new GSTMediaPlayer(source); 118 } catch (Exception e) { 119 if (Logger.canLog(Logger.DEBUG)) { 120 Logger.logMsg(Logger.DEBUG, "GSTPlatform caught exception while creating media player: "+e); 121 } 122 return null; 123 } 124 125 // Special case for H.264 decoding on Mac OS X. 126 if (HostUtils.isMacOSX()) { 127 String contentType = source.getContentType(); 128 if ("video/mp4".equals(contentType) || "video/x-m4v".equals(contentType) 129 || source.getStringLocation().endsWith(".m3u8")) 130 { 131 // Block until player transitions to READY or HALTED. 132 133 // Timeouts in milliseconds. 134 String scheme = source.getURI().getScheme(); 135 final long timeout = (scheme.equals("http") || scheme.equals("https")) ? 136 60000L : 5000L; 137 final long iterationTime = 50L; 138 long timeWaited = 0L; 139 140 final Object lock = new Object(); 141 PlayerState state = player.getState(); 142 143 while (timeWaited < timeout && 144 (state == PlayerState.UNKNOWN || state == PlayerState.STALLED)) { 145 try { 146 synchronized(lock) { 147 lock.wait(iterationTime); 148 timeWaited += iterationTime; 149 } 150 } catch (InterruptedException ex) { 151 // Ignore it. 152 } 153 154 // Check if error event was set. We will not go to READY or 155 // HALT state in this case. Error event is basically same 156 // as HALT. 157 if (player.isErrorEventCached()) { 158 break; 159 } 160 161 state = player.getState(); 162 } 163 164 // If the player is not READY, an error occurred. 165 if (player.getState() != PlayerState.READY) { 166 player.dispose(); 167 player = null; 168 } 169 } 170 } 171 return player; 172 } 173 174 /** 175 * Initialize the native peer of this media manager. 176 * 177 * @return A status code. 178 */ 179 private static native int gstInitPlatform(); 180 }