changeset 5412:5e2ca3c5b155

Merge
author mhowe
date Mon, 21 Oct 2013 15:18:12 -0700
parents b5b14c01d4d6 9da8553e3fe4
children 50cde3719e4d 10fb5c46af44
files
diffstat 1119 files changed, 578290 insertions(+), 33 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Mon Oct 21 12:37:32 2013 -0700
+++ b/.hgtags	Mon Oct 21 15:18:12 2013 -0700
@@ -100,3 +100,4 @@
 ad10ea1df81d77856c26ddce49d0476f14c53184 8.0-b109
 0eb503d2b56761a35de73329cacda0c4d8515731 8.0-b110
 e6331b4daf158532bcd40dff38eb91500075cc72 8.0-b111
+915737d79cc6afbb40844c97d4d64e924fc781b9 8.0-b112
--- a/build.gradle	Mon Oct 21 12:37:32 2013 -0700
+++ b/build.gradle	Mon Oct 21 15:18:12 2013 -0700
@@ -119,7 +119,6 @@
     return out.toString().trim();
 }
 
-
 void loadProperties(String sourceFileName) {
     def config = new Properties()
     def propFile = new File(sourceFileName)
@@ -298,13 +297,13 @@
     apply from: supplementalPreBuildFile
 }
 
-// COMPILE_WEBKIT specifies whether to build all of webkit. COMPILE_GSTREAMER
-// specifies whether to build GStreamer. Both of these can be set by a
+// COMPILE_WEBKIT specifies whether to build all of webkit. COMPILE_MEDIA
+// specifies whether to build all of media. Both of these can be set by a
 // command line property
 defineProperty("COMPILE_WEBKIT", "false")
-defineProperty("COMPILE_GSTREAMER", "false")
+defineProperty("COMPILE_MEDIA", "false")
 if (COMPILE_WEBKIT instanceof String) ext.COMPILE_WEBKIT = Boolean.parseBoolean(COMPILE_WEBKIT)
-if (COMPILE_GSTREAMER instanceof String) ext.COMPILE_GSTREAMER = Boolean.parseBoolean(COMPILE_GSTREAMER)
+if (COMPILE_MEDIA instanceof String) ext.COMPILE_MEDIA = Boolean.parseBoolean(COMPILE_MEDIA)
 
 // COMPILE_PANGO specifies whether to build javafx-font-pango.
 defineProperty("COMPILE_PANGO", "false")
@@ -931,7 +930,7 @@
 allprojects {
     // We want to configure all projects as java projects and use the same compile settings
     // etc, except for the root project which we just want to ignore (and for now media)
-    if (project == rootProject || project.name == "media") return
+    if (project == rootProject) return
     // All of our projects are java projects
     apply plugin: "java"
     sourceCompatibility = 1.8
@@ -1070,7 +1069,7 @@
         antlr3 group: "org.antlr", name: "antlr-runtime",  version: "3.1.3"
         antlr3 group: "org.antlr", name: "stringtemplate", version: "3.2"
     }
-    
+
     // Create a single "native" task which will depend on all the individual native tasks for graphics
     project.ext.nativeAllTask = task("native", group: "Build", description: "Compiles and Builds all native libraries for Graphics");
     project.ext.cleanNativeAllTask = task("cleanNative", group: "Build", description: "Clean all native libraries and objects for Graphics");
@@ -1400,14 +1399,13 @@
 project(":builders") {
     sourceCompatibility = 1.7
 
-    if (!COMPILE_SWING)  sourceSets.main.java.exclude ("**/swing/**")
-    if (!COMPILE_SWT)    sourceSets.main.java.exclude ("**/swt/**")
+    if (!COMPILE_SWING) sourceSets.main.java.exclude ("**/swing/**")
+    if (!COMPILE_SWT)   sourceSets.main.java.exclude ("**/swt/**")
     if (!COMPILE_WEBKIT) sourceSets.main.java.exclude ("**/web/**")
-    if (!BUILD_CLOSED)   sourceSets.main.java.exclude ("**/media/**")
 
     dependencies {
         compile BUILD_SRC, project(":base"), project(":graphics"),
-                project(":controls"), project(":swt"), project(":swing"), project(":web")
+                project(":controls"), project(":swt"), project(":swing"), project(":media"), project(":web")
         testCompile project(":graphics").sourceSets.test.output
     }
     test {
@@ -1640,6 +1638,216 @@
     }
 }
 
+project(":media") {
+    configurations {
+        media
+    }
+
+    dependencies {
+        compile BUILD_SRC, project(":base"), project(":graphics")
+    }
+
+    sourceSets {
+        tools {
+            java.srcDir "src/tools/java"
+        }
+    }
+
+    compileToolsJava {
+        enabled = COMPILE_MEDIA
+        classpath = sourceSets.main.output;
+    }
+
+    project.ext.makeJobsFlag = IS_WINDOWS && IS_DEBUG_NATIVE ? "-j1" : "-j5";
+    project.ext.buildType = IS_DEBUG_NATIVE ? "Debug" : "Release";
+
+    def nativeSrcDir = file("${projectDir}/src/main/native")
+    def generatedHeadersDir = file("${buildDir}/generated-src/headers")
+    
+    task generateHeaders(dependsOn: compileJava) {
+        enabled = COMPILE_MEDIA
+        doLast {
+            def classpath = sourceSets.main.output;
+            mkdir generatedHeadersDir;
+
+            def classesList = ["com.sun.media.jfxmedia.logging.Logger",
+                             "com.sun.media.jfxmedia.track.AudioTrack",
+                             "com.sun.media.jfxmedia.control.VideoDataBuffer",
+                             "com.sun.media.jfxmedia.control.VideoFormat\$FormatTypes",
+                             "com.sun.media.jfxmediaimpl.NativeAudioClip",
+                             "com.sun.media.jfxmediaimpl.NativeMediaPlayer",
+                             "com.sun.media.jfxmediaimpl.NativeVideoBuffer",
+                             "com.sun.media.jfxmediaimpl.platform.gstreamer.GSTPlatform",
+                             "com.sun.media.jfxmediaimpl.platform.gstreamer.GSTMedia",
+                             "com.sun.media.jfxmediaimpl.platform.gstreamer.GSTMediaPlayer",
+                             "com.sun.media.jfxmediaimpl.platform.gstreamer.GSTAudioEqualizer",
+                             "com.sun.media.jfxmediaimpl.platform.gstreamer.GSTEqualizerBand",
+                             "com.sun.media.jfxmediaimpl.platform.gstreamer.GSTAudioSpectrum"]
+            if (IS_MAC) {
+                classesList.addAll( ["com.sun.media.jfxmediaimpl.platform.osx.OSXPlatform",
+                                     "com.sun.media.jfxmediaimpl.platform.osx.OSXMedia",
+                                     "com.sun.media.jfxmediaimpl.platform.osx.OSXMediaPlayer"] );
+            }
+            exec {
+                commandLine ("${JAVAH}", "-J-Djava.ext.dirs=", "-d", "${generatedHeadersDir}", "-classpath", "${classpath.asPath}");
+                args classesList;
+            }
+        }
+    }
+    
+    task generateMediaErrorHeader(dependsOn: [compileToolsJava, compileJava]) {
+        enabled = COMPILE_MEDIA
+        doLast {
+            def classpath = files(sourceSets.main.output, sourceSets.tools.output);
+            def sourcepath = sourceSets.main.java.srcDirs;
+            def headerpath = file("$generatedHeadersDir/jfxmedia_errors.h");
+            def srcRoot = (sourcepath.toArray())[0];
+
+            mkdir generatedHeadersDir;
+
+            exec {
+                commandLine("$JAVA", "-Djava.ext.dirs=", "-classpath", "${classpath.asPath}");
+                args("headergen.HeaderGen", "$headerpath", "$srcRoot");
+            }
+        }
+    }
+
+    task buildNativeTargets {
+        enabled = COMPILE_MEDIA
+    }
+    
+    compileTargets { t->        
+        def nativeOutputDir = file("${buildDir}/native/${t.name}")
+        def projectDir = t.name.startsWith("arm") ? "linux" : t.name
+        def mediaProperties = project.rootProject.ext[t.upper].media
+        
+        def buildNative = task("build${t.capital}Native", dependsOn: [generateHeaders, generateMediaErrorHeader]) {
+            enabled = COMPILE_MEDIA
+            doLast {
+                exec {
+                    commandLine ("make", "${makeJobsFlag}", "-C", "${nativeSrcDir}/jfxmedia/projects/${projectDir}")
+                    args("JAVA_HOME=${JAVA_HOME}", "GENERATED_HEADERS_DIR=${generatedHeadersDir}",
+                         "OUTPUT_DIR=${nativeOutputDir}", "BUILD_TYPE=${buildType}", "BASE_NAME=jfxmedia")
+
+                    if (t.name == "win") {
+                        environment(WINDOWS_NATIVE_COMPILE_ENVIRONMENT)
+                        args(IS_64 ? "ARCH=x64" : "ARCH=x32")
+                    } else {
+                        args ("CC=${mediaProperties.compiler}", "LINK=${mediaProperties.linker}", "LIB=${mediaProperties.lib}")
+
+                        if (t.name.startsWith("arm"))
+                            args("EXTRA_CFLAGS=${mediaProperties.extra_cflags}", "EXTRA_LDFLAGS=${mediaProperties.extra_ldflags}")
+                        else
+                            args("HOST_COMPILE=1")
+                    }
+                }
+            }
+        }        
+        
+        if (!t.name.startsWith("arm")) {
+            // Building GStreamer
+            def buildGStreamer = task("build${t.capital}GStreamer") {
+                enabled = COMPILE_MEDIA
+                doLast {
+                    exec {
+                        commandLine ("make", "${makeJobsFlag}", "-C", "${nativeSrcDir}/gstreamer/projects/${projectDir}/gstreamer-lite")
+                        args("OUTPUT_DIR=${nativeOutputDir}", "BUILD_TYPE=${buildType}", "BASE_NAME=gstreamer-lite")
+
+                        if (t.name == "win") {
+                            environment(WINDOWS_NATIVE_COMPILE_ENVIRONMENT)
+                            args(IS_64 ? "ARCH=x64" : "ARCH=x32")
+                        } else
+                            args ("CC=${mediaProperties.compiler}", "LINK=${mediaProperties.linker}", "LIB=${mediaProperties.lib}")
+                    }
+                }
+            }
+
+            def buildPlugins = task("build${t.capital}Plugins", dependsOn: buildGStreamer) {
+                enabled = COMPILE_MEDIA
+
+                if (!project.ext.properties.containsKey("ON2_SRCDIR"))
+                    project.ext.ON2_SRCDIR = "";
+
+                if (!project.ext.properties.containsKey("ON2_LIB"))
+                    project.ext.ON2_LIB = "";
+
+                doLast {
+                    exec {
+                        commandLine ("make", "${makeJobsFlag}", "-C", "${nativeSrcDir}/gstreamer/projects/${projectDir}/fxplugins")
+                        args("OUTPUT_DIR=${nativeOutputDir}", "BUILD_TYPE=${buildType}", "BASE_NAME=fxplugins", 
+                             "ON2_SRCDIR=${project.ext.ON2_SRCDIR}", "ON2_LIB=${project.ext.ON2_LIB}")
+
+                        if (t.name == "win") {
+                            Map winEnv = new HashMap(WINDOWS_NATIVE_COMPILE_ENVIRONMENT)
+
+                            String sdkDir = System.getenv("BASECLASSES_SDK_DIR");
+                            if (sdkDir == null)
+                            {
+                                sdkDir = "C:/Program Files/Microsoft SDKs/Windows/v7.1" // Default value
+                                winEnv["BASECLASSES_SDK_DIR"] = sdkDir
+                            }
+                            environment(winEnv)
+
+                            args(IS_64 ? "ARCH=x64" : "ARCH=x32")
+                        } else
+                            args ("CC=${mediaProperties.compiler}", "LINK=${mediaProperties.linker}", "LIB=${mediaProperties.lib}")
+                    }
+                }
+            }
+            
+            buildNative.dependsOn buildPlugins
+
+            if (t.name == "linux") {
+                def buildAVPlugin = task( "buildAVPlugin", dependsOn: [buildPlugins]) {
+                    enabled = COMPILE_MEDIA
+
+                    if (!project.ext.properties.containsKey("LIBAV"))
+                        project.ext.LIBAV = "";
+
+                    doLast {
+                        // Building fxavcodec plugin (libav plugin)
+                        exec {
+                            commandLine ("make", "${makeJobsFlag}", "-C", "${nativeSrcDir}/gstreamer/projects/linux/avplugin")
+                            args("CC=${mediaProperties.compiler}", "OUTPUT_DIR=${nativeOutputDir}", "BUILD_TYPE=${buildType}", 
+                                     "BASE_NAME=avplugin", "LIBAV_DIR=${project.ext.LIBAV}")
+                        }
+                    }
+                }
+                buildNative.dependsOn buildAVPlugin
+            }
+
+            if (t.name == "win" || t.name == "mac") {
+                def buildGlib = task("build${t.capital}Glib") {
+                    enabled = COMPILE_MEDIA
+                    doLast {
+                        exec {
+                            commandLine ("make", "${makeJobsFlag}", "-C", "${nativeSrcDir}/gstreamer/projects/${projectDir}/glib-lite")
+                            args("OUTPUT_DIR=${nativeOutputDir}", "BUILD_TYPE=${buildType}", "BASE_NAME=glib-lite")
+
+                            if (t.name == "win") {
+                                environment(WINDOWS_NATIVE_COMPILE_ENVIRONMENT)
+                                args(IS_64 ? "ARCH=x64" : "ARCH=x32")
+                            } else
+                                args ("CC=${mediaProperties.compiler}", "LINK=${mediaProperties.linker}", "LIB=${mediaProperties.lib}")
+                        }
+                    }
+                }
+                buildGStreamer.dependsOn buildGlib
+            }
+        }
+        
+        buildNativeTargets.dependsOn buildNative
+    }
+ 
+    jar {
+        exclude("headergen/**")
+
+        dependsOn compileJava
+        if (COMPILE_MEDIA)
+            dependsOn buildNativeTargets
+    }
+}
+
 allprojects {
     // The following block is a workaround for the fact that presently Gradle
     // can't set the -XDignore.symbol.file flag, because it appears that the
@@ -1880,9 +2088,17 @@
              "modules/graphics/build/classes/jsl-decora",
              "modules/graphics/build/resources/jsl-decora",
              "modules/graphics/build/classes/jsl-prism",
-             "modules/graphics/build/resources/jsl-prism");
+             "modules/graphics/build/resources/jsl-prism",
+             "modules/media/build/classes/main",
+             "modules/media/build/resources/main")
         if (COMPILE_SWING) from ("modules/swing/build/classes/main", "modules/swing/build/resources/main")
         if (COMPILE_SWT) from ("modules/swt/build/classes/main", "modules/swt/build/resources/main")
+
+        if (t.name != 'mac') 
+            exclude ("modules/media/build/classes/main/com/sun/media/jfxmediaimpl/platform/osx/**")
+        if (t.name != 'ios') 
+            exclude ("modules/media/build/classes/main/com/sun/media/jfxmediaimpl/platform/ios/**")
+
         if (t.name == 'android') {
             from ("modules/web/build/classes/android",
                   "modules/web/build/resources/android",
@@ -1946,6 +2162,22 @@
                         from ("$LIBRARY_STUB/${library('jfxwebkit')}")
                     }
                 }
+
+                if (COMPILE_MEDIA) {
+                    [ "fxplugins", "gstreamer-lite", "jfxmedia" ].each { name ->
+                        from ("modules/media/build/native/${t.name}/${CONF}/${library(name)}") }
+                    
+                    if (t.name == "linux") from ("modules/media/build/native/${t.name}/${CONF}/${library("avplugin")}")
+                    else from ("modules/media/build/native/${t.name}/${CONF}/${library("glib-lite")}")
+
+                } else {
+                    [ "fxplugins", "gstreamer-lite", "jfxmedia" ].each { name ->
+                        from ("$LIBRARY_STUB/${library(name)}") }                        
+
+                    if (t.name == "linux") from ("$LIBRARY_STUB/${library("avplugin")}")
+                    else from ("$LIBRARY_STUB/${library("glib-lite")}")
+                }
+                
                 def libDest = targetProperties.libDest
                 into ("build/${t.name}-sdk/rt/$libDest")
             }
@@ -2109,17 +2341,10 @@
         webkit
     }
     dependencies {
-        compile project(":base"), project(":graphics"), project(":controls")
-        testCompile files("../../../artifacts/sdk/rt/lib/ext/jfxrt.jar")
+        compile project(":base"), project(":graphics"), project(":controls"), project(":media")
     }
     
     compileJava.enabled = COMPILE_WEBKIT
-    if (BUILD_CLOSED) {
-        compileJava.dependsOn compileMediaJava
-        compileJava.classpath += files(
-                "../media/build/classes/main",
-                "$jfxTopDir/media/jfxmedia/dist/jfxmedia.jar")
-    }
     
     task generateHeaders(dependsOn: compileJava) {
         doLast {
--- a/buildSrc/android.gradle	Mon Oct 21 12:37:32 2013 -0700
+++ b/buildSrc/android.gradle	Mon Oct 21 15:18:12 2013 -0700
@@ -540,3 +540,8 @@
 ANDROID.fontT2K.linker = linker
 ANDROID.fontT2K.linkFlags = [linkFlags, "-lstdc++"].flatten()
 ANDROID.fontT2K.lib = "javafx_font_t2k"
+
+ANDROID.media = [:]
+ANDROID.media.compiler = compiler
+ANDROID.media.linker = linker
+ANDROID.media.lib = file("$compilerHome/bin/${toolchainArchs[0]}-ar").getAbsolutePath()
\ No newline at end of file
--- a/buildSrc/armv6hf.gradle	Mon Oct 21 12:37:32 2013 -0700
+++ b/buildSrc/armv6hf.gradle	Mon Oct 21 15:18:12 2013 -0700
@@ -140,7 +140,7 @@
     "-I$sdk/usr/include/gstreamer-0.10",
     "-I$sdk/usr/include/glib-2.0",
     "-I$sdk/usr/lib/arm-linux-gnueabihf/glib-2.0/include",
-    "-DENABLE.nativeSource=1", "-DENABLE_GST_FFMPEG=1"].flatten()
+    "-DENABLE_NATIVE_SOURCE=1", "-DENABLE_GST_FFMPEG=1"].flatten()
 def mediaLFlags = [extraLFlags, "-lgstreamer-0.10", "-lgstapp-0.10",
     "-lgstbase-0.10", "-lglib-2.0", "-lgobject-2.0", "-lgmodule-2.0", "-lgthread-2.0"].flatten()
 
@@ -452,3 +452,9 @@
 ARMV6HF.webkit.strip    = file("$compilerHome/bin/arm-linux-gnueabihf-strip").getAbsolutePath()
 ARMV6HF.webkit.ccFlags  = extraCFlags.join(' ')
 ARMV6HF.webkit.linkFlags = extraLFlags.join(' ')
+
+ARMV6HF.media = [:]
+ARMV6HF.media.compiler = compiler
+ARMV6HF.media.linker = linker
+ARMV6HF.media.extra_cflags = mediaCFlags.join(' ')
+ARMV6HF.media.extra_ldflags = mediaLFlags.join(' ')
\ No newline at end of file
--- a/buildSrc/armv6sf.gradle	Mon Oct 21 12:37:32 2013 -0700
+++ b/buildSrc/armv6sf.gradle	Mon Oct 21 15:18:12 2013 -0700
@@ -153,8 +153,8 @@
 def mediaCFlags = [extraCFlags,
     "-I$sdk/usr/include/gstreamer-0.10",
     "-I$sdk/usr/include/glib-2.0",
-    "-I$sdk/usr/lib/arm-linux-gnueabihf/glib-2.0/include",
-    "-DENABLE.nativeSource=1", "-DENABLE_GST_FFMPEG=1"].flatten()
+    "-I$sdk/usr/lib/glib-2.0/include",
+    "-DENABLE_NATIVE_SOURCE=1", "-DENABLE_GST_FFMPEG=1"].flatten()
 def mediaLFlags = [extraLFlags, "-lgstreamer-0.10", "-lgstapp-0.10",
     "-lgstbase-0.10", "-lglib-2.0", "-lgobject-2.0", "-lgmodule-2.0", "-lgthread-2.0"].flatten()
 
@@ -468,3 +468,9 @@
 ARMV6SF.webkit.strip    = file("$compilerHome/bin/arm-linux-gnueabi-strip").getAbsolutePath()
 ARMV6SF.webkit.ccFlags  = extraCFlags.join(' ')
 ARMV6SF.webkit.linkFlags = extraLFlags.join(' ')
+
+ARMV6SF.media = [:]
+ARMV6SF.media.compiler = compiler
+ARMV6SF.media.linker = linker
+ARMV6SF.media.extra_cflags = mediaCFlags.join(' ')
+ARMV6SF.media.extra_ldflags = mediaLFlags.join(' ')
\ No newline at end of file
--- a/buildSrc/ios.gradle	Mon Oct 21 12:37:32 2013 -0700
+++ b/buildSrc/ios.gradle	Mon Oct 21 15:18:12 2013 -0700
@@ -379,3 +379,8 @@
         }
     }
 }
+
+IOS.media =[:]
+IOS.media.compiler = compiler
+IOS.media.linker = linker
+IOS.media.lib = linker
--- a/buildSrc/linux.gradle	Mon Oct 21 12:37:32 2013 -0700
+++ b/buildSrc/linux.gradle	Mon Oct 21 15:18:12 2013 -0700
@@ -234,3 +234,8 @@
 LINUX.fontPango.linker = linker
 LINUX.fontPango.linkFlags = [linkFlags, pangoLinkFlags].flatten()
 LINUX.fontPango.lib = "javafx-font-pango"
+
+LINUX.media = [:]
+LINUX.media.compiler = compiler
+LINUX.media.linker = linker
+LINUX.media.lib = "ar"
\ No newline at end of file
--- a/buildSrc/mac.gradle	Mon Oct 21 12:37:32 2013 -0700
+++ b/buildSrc/mac.gradle	Mon Oct 21 15:18:12 2013 -0700
@@ -205,3 +205,8 @@
 MAC.fontT2K.linker = linker
 MAC.fontT2K.linkFlags = [linkFlags].flatten()
 MAC.fontT2K.lib = "javafx_font_t2k"
+
+MAC.media = [:]
+MAC.media.compiler = compiler
+MAC.media.linker = linker
+MAC.media.lib = "libtool"
--- a/buildSrc/x86egl.gradle	Mon Oct 21 12:37:32 2013 -0700
+++ b/buildSrc/x86egl.gradle	Mon Oct 21 15:18:12 2013 -0700
@@ -400,3 +400,8 @@
 X86EGL.fontPango.linker = linker
 X86EGL.fontPango.linkFlags = [linkFlags, pangoLinkFlags].flatten()
 X86EGL.fontPango.lib = "javafx_font_pango"
+
+X86EGL.media =[:]
+X86EGL.media.compiler = compiler
+X86EGL.media.linker = linker
+X86EGL.media.lib = "ar"
\ No newline at end of file
--- a/gradle.properties.template	Mon Oct 21 12:37:32 2013 -0700
+++ b/gradle.properties.template	Mon Oct 21 15:18:12 2013 -0700
@@ -38,7 +38,7 @@
 # GStreamer, uncomment the appropriate lines below.
 
 #COMPILE_WEBKIT = true
-#COMPILE_GSTREAMER = true
+#COMPILE_MEDIA = true
 
 # The building of JavaDoc takes time. By default we disable the building of JavaDoc
 # so as to speed up the time in incremental builds. Uncomment this flag in order to
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/LocalClipboard.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2013, 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.javafx.tk;
+
+import java.security.AccessControlContext;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import javafx.scene.image.Image;
+import javafx.scene.input.DataFormat;
+import javafx.scene.input.TransferMode;
+import javafx.util.Pair;
+
+final class LocalClipboard implements TKClipboard {
+    private final Map<DataFormat, Object> values;
+
+    public LocalClipboard() {
+        values = new HashMap<DataFormat, Object>();
+    }
+
+    @Override
+    public void setSecurityContext(final AccessControlContext ctx) {
+        // ctx not needed
+    }
+
+    @Override
+    public Set<DataFormat> getContentTypes() {
+        return Collections.unmodifiableSet(
+                   new HashSet<DataFormat>(values.keySet()));
+    }
+
+    @Override
+    public boolean putContent(final Pair<DataFormat, Object>... content) {
+        for (final Pair<DataFormat, Object> pair: content) {
+            if (pair.getKey() == null) {
+                throw new NullPointerException(
+                        "Clipboard.putContent: null data format");
+            }
+            if (pair.getValue() == null) {
+                throw new NullPointerException(
+                        "Clipboard.putContent: null data");
+            }
+        }
+
+        // all OK, replace clipboard content
+        values.clear();
+        for (final Pair<DataFormat, Object> pair: content) {
+            values.put(pair.getKey(), pair.getValue());
+        }
+
+        return true;
+    }
+
+    @Override
+    public Object getContent(final DataFormat dataFormat) {
+        return values.get(dataFormat);
+    }
+
+    @Override
+    public boolean hasContent(final DataFormat dataFormat) {
+        return values.containsKey(dataFormat);
+    }
+
+    @Override
+    public Set<TransferMode> getTransferModes() {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public void setDragView(final Image image) {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public void setDragViewOffsetX(final double offsetX) {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public void setDragViewOffsetY(final double offsetY) {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public Image getDragView() {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public double getDragViewOffsetX() {
+        throw new IllegalStateException();
+    }
+
+    @Override
+    public double getDragViewOffsetY() {
+        throw new IllegalStateException();
+    }
+}
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/Toolkit.java	Mon Oct 21 12:37:32 2013 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/Toolkit.java	Mon Oct 21 15:18:12 2013 -0700
@@ -602,6 +602,10 @@
 
     public abstract TKClipboard getSystemClipboard();
 
+    public TKClipboard createLocalClipboard() {
+        return new LocalClipboard();
+    }
+
     public abstract TKSystemMenu getSystemMenu();
 
     public abstract TKClipboard getNamedClipboard(String name);
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/GlassScene.java	Mon Oct 21 12:37:32 2013 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/GlassScene.java	Mon Oct 21 15:18:12 2013 -0700
@@ -48,9 +48,14 @@
 import com.sun.prism.impl.PrismSettings;
 import com.sun.prism.paint.Color;
 import com.sun.prism.paint.Paint;
+import sun.misc.JavaSecurityAccess;
+import sun.misc.SharedSecrets;
 
 abstract class GlassScene implements TKScene {
 
+    private static final JavaSecurityAccess javaSecurityAccess =
+            SharedSecrets.getJavaSecurityAccess();
+
     private GlassStage stage;
 
     protected TKSceneListener sceneListener;
@@ -100,7 +105,16 @@
         if (accessCtrlCtx != null) {
             throw new RuntimeException("Scene security context has been already set!");
         }
-        accessCtrlCtx = ctx;
+        AccessControlContext acc = AccessController.getContext();
+        // JDK doesn't provide public APIs to get ACC intersection,
+        // so using this ugly workaround
+        accessCtrlCtx = javaSecurityAccess.doIntersectionPrivilege(
+                new PrivilegedAction<AccessControlContext>() {
+                    @Override
+                    public AccessControlContext run() {
+                        return AccessController.getContext();
+                    }
+                }, acc, ctx);
     }
 
     public void waitForRenderingToComplete() {
--- a/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/GlassStage.java	Mon Oct 21 12:37:32 2013 -0700
+++ b/modules/graphics/src/main/java/com/sun/javafx/tk/quantum/GlassStage.java	Mon Oct 21 15:18:12 2013 -0700
@@ -40,8 +40,14 @@
 import com.sun.javafx.tk.TKStageListener;
 import com.sun.javafx.tk.Toolkit;
 
+import sun.misc.JavaSecurityAccess;
+import sun.misc.SharedSecrets;
+
 abstract class GlassStage implements TKStage {
 
+    private static final JavaSecurityAccess javaSecurityAccess =
+            SharedSecrets.getJavaSecurityAccess();
+
     // A list of all GlassStage objects regardless of visibility.
     private static final List<GlassStage> windows = new ArrayList<>();
 
@@ -107,7 +113,16 @@
         if (accessCtrlCtx != null) {
             throw new RuntimeException("Stage security context has been already set!");
         }
-        accessCtrlCtx = ctx;
+        AccessControlContext acc = AccessController.getContext();
+        // JDK doesn't provide public APIs to get ACC intersection,
+        // so using this ugly workaround
+        accessCtrlCtx = javaSecurityAccess.doIntersectionPrivilege(
+            new PrivilegedAction<AccessControlContext>() {
+                @Override
+                public AccessControlContext run() {
+                    return AccessController.getContext();
+                }
+            }, acc, ctx);
     }
 
     @Override public void requestFocus() {
--- a/modules/graphics/src/main/java/javafx/scene/input/Clipboard.java	Mon Oct 21 12:37:32 2013 -0700
+++ b/modules/graphics/src/main/java/javafx/scene/input/Clipboard.java	Mon Oct 21 15:18:12 2013 -0700
@@ -37,6 +37,7 @@
 
 import com.sun.javafx.tk.TKClipboard;
 import com.sun.javafx.tk.Toolkit;
+import java.security.AllPermission;
 
 /**
  * Represents an operating system clipboard, on which data may be placed during, for
@@ -158,20 +159,23 @@
      * the system will invoke the provided callback to stream the image data over to the client.
      */
 
-    private static Clipboard systemClipboard = null;
+    private final AccessControlContext acc = AccessController.getContext();
 
-    private final AccessControlContext acc = AccessController.getContext();
-    
     /**
      * Gets the current system clipboard, through which data can be stored and
      * retrieved. There is ever only one system clipboard for a JavaFX application.
      * @return The single system clipboard, used for cut / copy / paste operations
      */
     public static Clipboard getSystemClipboard() {
-        if (systemClipboard == null) {
-            systemClipboard = new Clipboard(Toolkit.getToolkit().getSystemClipboard());
+        try {
+            final SecurityManager securityManager = System.getSecurityManager();
+            if (securityManager != null) {
+                securityManager.checkPermission(new AllPermission());
+            }
+            return getSystemClipboardImpl();
+        } catch (final SecurityException e) {
+            return getLocalClipboardImpl();
         }
-        return systemClipboard;
     }
 
     TKClipboard peer;
@@ -390,4 +394,24 @@
     public boolean impl_contentPut() {
         return contentPut;
     }
+
+    private static Clipboard systemClipboard;
+
+    private static synchronized Clipboard getSystemClipboardImpl() {
+        if (systemClipboard == null) {
+            systemClipboard =
+                    new Clipboard(Toolkit.getToolkit().getSystemClipboard());
+        }
+        return systemClipboard;
+    }
+
+    private static Clipboard localClipboard;
+
+    private static synchronized Clipboard getLocalClipboardImpl() {
+        if (localClipboard == null) {
+            localClipboard =
+                    new Clipboard(Toolkit.getToolkit().createLocalClipboard());
+        }
+        return localClipboard;
+    }
 }
Binary file modules/media/src/main/docs/javafx/scene/media/doc-files/mediaplayerstatus.png has changed
Binary file modules/media/src/main/docs/javafx/scene/media/doc-files/mediaview.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/javafx/media/PrismMediaFrameHandler.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2011, 2013, 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.javafx.media;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.WeakHashMap;
+import com.sun.glass.ui.Screen;
+import com.sun.javafx.tk.RenderJob;
+import com.sun.javafx.tk.Toolkit;
+import com.sun.media.jfxmedia.control.VideoDataBuffer;
+import com.sun.media.jfxmedia.control.VideoFormat;
+import com.sun.prism.Graphics;
+import com.sun.prism.GraphicsPipeline;
+import com.sun.prism.MediaFrame;
+import com.sun.prism.PixelFormat;
+import com.sun.prism.ResourceFactoryListener;
+import com.sun.prism.Texture;
+
+/**
+ * Prism-specific subclass for handling media frames. The frames uploaded
+ * into per-Screen textures, updated on every frame.
+ *
+ */
+public class PrismMediaFrameHandler implements ResourceFactoryListener {
+    private final Map<Screen, TextureMapEntry> textures = new WeakHashMap<>(1);
+
+    private static Map<Object, PrismMediaFrameHandler> handlers;
+    public synchronized static PrismMediaFrameHandler getHandler(Object provider) {
+        if (provider == null) {
+            throw new IllegalArgumentException("provider must be non-null");
+        }
+        if (handlers == null) {
+            handlers = new WeakHashMap<>(1);
+        }
+        PrismMediaFrameHandler ret = handlers.get(provider);
+        if (ret == null) {
+            ret = new PrismMediaFrameHandler(provider);
+            handlers.put(provider, ret);
+        }
+        return ret;
+    }
+
+    private boolean registeredWithFactory = false;
+    private PrismMediaFrameHandler(Object provider) {
+    }
+
+    
+    /* NOTE: The following methods will only ever happen on one thread, so thread
+     * safety should not be a concern here.
+     */
+    
+    /**
+     * This should only ever be called during a render cycle. Any other time it
+     * will return null.
+     * @param g the Graphics context about to be rendered into
+     * @return the current media texture valid for rendering into <code>g</code>
+     * or null if called outside a render cycle
+     */
+    public Texture getTexture(Graphics g, VideoDataBuffer currentFrame) {
+        Screen screen = g.getAssociatedScreen();
+        TextureMapEntry tme = textures.get(screen);
+        
+        if (null == currentFrame) {
+            // null frame, remove the existing texture
+            if (textures.containsKey(screen)) {
+                textures.remove(screen);
+            }
+            return null;
+        }
+        
+        if (null == tme) {
+            // we need to create a new texture for this graphics context
+            tme = new TextureMapEntry();
+            textures.put(screen, tme);
+        }
+
+        if (tme.texture != null) {
+            tme.texture.lock();
+            if (tme.texture.isSurfaceLost()) {
+                tme.texture = null;
+            }
+        }
+        
+        // check if it needs to be updated
+        if (null == tme.texture || tme.lastFrameTime != currentFrame.getTimestamp()) {
+            updateTexture(g, currentFrame, tme);
+        }
+
+        return tme.texture;
+    }
+
+    private void updateTexture(Graphics g, VideoDataBuffer vdb, TextureMapEntry tme)
+    {
+        Screen screen = g.getAssociatedScreen();
+
+        // reset texture if the encoded size changes
+        if (tme.texture != null &&
+            (tme.encodedWidth != vdb.getEncodedWidth() ||
+             tme.encodedHeight != vdb.getEncodedHeight()))
+        {
+            tme.texture.dispose();
+            tme.texture = null;
+        }
+
+        PrismFrameBuffer prismBuffer = new PrismFrameBuffer(vdb);
+        if (tme.texture == null) {
+            if (!registeredWithFactory) {
+                // make sure we've registered with the resource factory so we know
+                // when to purge old textures
+                GraphicsPipeline.getDefaultResourceFactory().addFactoryListener(this);
+                registeredWithFactory = true;
+            }
+            
+            tme.texture = GraphicsPipeline.getPipeline().
+                getResourceFactory(screen).
+                    createTexture(prismBuffer);
+            tme.encodedWidth = vdb.getEncodedWidth();
+            tme.encodedHeight = vdb.getEncodedHeight();
+        }
+        
+        // upload frame data, check for null in case createTexture fails
+        if (tme.texture != null) {
+            tme.texture.update(prismBuffer, false);
+        }
+        tme.lastFrameTime = vdb.getTimestamp();
+    }
+
+    private void releaseData() {
+        for (TextureMapEntry tme : textures.values()) {
+            if (tme != null && tme.texture != null) {
+                tme.texture.dispose();
+            }
+        }
+        textures.clear();
+    }
+    
+    private RenderJob releaseRenderJob = new RenderJob(new Runnable() {
+            public void run() {
+                releaseData();
+            }
+        });
+
+    /**
+     * Call this when you no longer need to render movie frames, for example
+     * when playback stops.
+     */
+    public void releaseTextures() {
+        Toolkit tk = Toolkit.getToolkit();
+        tk.addRenderJob(releaseRenderJob);
+    }
+
+    public void factoryReset() {
+        releaseData();
+    }
+
+    public void factoryReleased() {
+        releaseData();
+    }
+    
+    /**
+     * Bridge class to avoid having to import JFXMedia into a bunch of prism
+     * code.
+     */
+    private class PrismFrameBuffer implements MediaFrame {
+        private final PixelFormat videoFormat;
+        private final VideoDataBuffer master;
+
+        public PrismFrameBuffer(VideoDataBuffer sourceBuffer) {
+            if (null == sourceBuffer) {
+                throw new NullPointerException();
+            }
+            
+            master = sourceBuffer;
+            switch (master.getFormat()) {
+                case BGRA_PRE:
+                    videoFormat = PixelFormat.INT_ARGB_PRE;
+                    break;
+                case YCbCr_420p:
+                    videoFormat = PixelFormat.MULTI_YCbCr_420;
+                    break;
+                case YCbCr_422:
+                    videoFormat = PixelFormat.BYTE_APPLE_422;
+                    break;
+                // ARGB isn't supported in prism, there's no corresponding PixelFormat
+                case ARGB:
+                default:
+                    throw new IllegalArgumentException("Unsupported video format "+master.getFormat());
+            }
+        }
+
+        public ByteBuffer getBuffer() {
+            return master.getBuffer();
+        }
+
+        public void holdFrame() {
+            master.holdFrame();
+        }
+        
+        public void releaseFrame() {
+            master.releaseFrame();
+        }
+
+        public PixelFormat getPixelFormat() {
+            return videoFormat;
+        }
+
+        public int getWidth() {
+            return master.getWidth();
+        }
+
+        public int getHeight() {
+            return master.getHeight();
+        }
+
+        public int getEncodedWidth() {
+            return master.getEncodedWidth();
+        }
+
+        public int getEncodedHeight() {
+            return master.getEncodedHeight();
+        }
+
+        public int planeCount() {
+            return master.getPlaneCount();
+        }
+
+        public int[] planeOffsets() {
+            return master.getPlaneOffsets();
+        }
+
+        public int offsetForPlane(int planeIndex) {
+            return master.getOffsetForPlane(planeIndex);
+        }
+
+        public int[] planeStrides() {
+            return master.getPlaneStrides();
+        }
+
+        public int strideForPlane(int planeIndex) {
+            return master.getStrideForPlane(planeIndex);
+        }
+
+        public MediaFrame convertToFormat(PixelFormat fmt) {
+            if (fmt == getPixelFormat()) {
+                return this;
+            }
+
+            // This method only supports conversion to INT_ARGB_PRE currently
+            if (fmt != PixelFormat.INT_ARGB_PRE) {
+                return null;
+            }
+
+            VideoDataBuffer newVDB = master.convertToFormat(VideoFormat.BGRA_PRE);
+            if (null == newVDB) {
+                return null;
+            }
+            return new PrismFrameBuffer(newVDB);
+        }
+    }
+    
+    private static class TextureMapEntry {
+        public double lastFrameTime = -1; // used to determine if we need to update
+        public Texture texture;
+        public int encodedWidth;
+        public int encodedHeight;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/AudioClip.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,431 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia;
+
+import com.sun.media.jfxmediaimpl.AudioClipProvider;
+import java.io.IOException;
+import java.net.URI;
+import java.io.FileNotFoundException;
+import java.net.URISyntaxException;
+
+/**
+ * <code>AudioClip</code>s are short segments of audio that can be
+ * played quickly and on-demand. Though loading of compressed audio formats may
+ * be supported, all AudioClip data is stored uncompressed internally to avoid
+ * decoding latency. The system is currently capable of playing up to
+ * 16 <code>AudioClip</code>s simultaneously.
+ *
+ * <p><b>Core AudioClip features:</b>
+ * <list>
+ *  <li>Near-zero latency playback, playback begins as soon as it's called, decoding is done at load time</li>
+ *  <li>Play clips up to ten seconds, though clips of any length may be loaded</li>
+ *  <li>Quick and simple "one shot" playback interface, just load the effect and play, cleanup is automatic</li>
+ *  <li>Play/pause/stop playback of effect, each playback instance is unique and can be controlled individually</li>
+ *  <li>Each effect can be played multiple times simultaneously</li>
+ *  <li>Loop playback (to some maximum amount?)</li>
+ *  <li>Vary rate/pitch</li>
+ *  <li>Playback volume</li>
+ *  <li>Effect balance</li>
+ *  <li>Pan left/right</li>
+ *  <li>Mix N audio effects for simultaneous playback (N TBD, start with 32)</li>
+ *  <li>Audio effect priority, lower priority effects get dropped first when playback threshold is reached</li>
+ * </list><br><hr><br>
+ *
+ * <b>Loading sound effects</b>
+ * <pre><code>
+ * SoundEffectBank soundBank = /&#42; TBD &#42;/ ;
+ * AudioClip ding = soundBank.effectNamed("ding");
+ * AudioClip dong = soundBank.effectNamed("dong");
+ * </code></pre>
+ *
+ * <b>OR</b><br>
+ *
+ * <pre><code>
+ * import javafx.scene.media.Media;
+ * import javafx.scene.media.AudioClip;
+ *
+ * AudioClip ding = new AudioClip("http://somehost.com/sounds/ding.aiff");
+ * AudioClip dong = new AudioClip("jar:http://host/path/some.jar!/resources/sounds/dong.aiff");
+ *
+ *      // Or you can use the ClassLoader to get a resource URI for resources bundled inside your application jar file
+ * AudioClip bonk = new AudioClip(this.getClass().getClassLoader().getResource("sounds/bonk.wav"));
+ *
+ *      // You can also load from a Media object
+ * Media whizMedia = new Media("http://somehost.com/sounds/whiz.aiff");
+ * AudioClip whiz = new AudioClip(whizMedia);
+ * </code></pre>
+ *
+ * <p><b>Playing sound effects</b>
+ * <p>Single play (fire and forget method):
+ * <pre>
+ * ding.play();
+ * dong.play(); // the two sounds play simultaneously, there is no further control over playback
+ * </pre>
+ *
+ * <br>Chaining multiple effects:
+ * <pre>
+ * ding.append(dong).play(); // ding and dong play sequentially, when finished the player is automatically disposed of
+ * ding.append(dong).append(ding).append(dong).append(ding).append(dong).play(); // really impatient person at the door :)
+ * AudioClip dingDong = ding.append(dong).flatten(); // dingDong is completely independent of ding and dong
+ * </pre>
+ *
+ */
+
+public abstract class AudioClip {
+    // default playback parameters
+    protected int clipPriority = 0;
+    protected int loopCount = 0;
+    protected double clipVolume = 1.0;
+    protected double clipBalance = 0.0;
+    protected double clipRate = 1.0;
+    protected double clipPan = 0.0;
+
+    /*
+     * Supported LPCM sample formats, all formats here can be loaded, but the
+     * underlying implementation may convert to an optimal format internally.
+     */
+    public static final int SAMPLE_FORMAT_S8 = 0;       /** Signed 8 bit LPCM */
+    public static final int SAMPLE_FORMAT_U8 = 1;       /** Unsigned 8 bit LPCM */
+    public static final int SAMPLE_FORMAT_S16BE = 2;    /** Signed 16 bit LPCM, big endian byte order */
+    public static final int SAMPLE_FORMAT_U16BE = 3;    /** Unsigned 16 bit LPCM, big endian byte order */
+    public static final int SAMPLE_FORMAT_S16LE = 4;    /** Signed 16 bit LPCM, little endian byte order */
+    public static final int SAMPLE_FORMAT_U16LE = 5;    /** Unsigned 16 bit LPCM, little endian byte order */
+    public static final int SAMPLE_FORMAT_S24BE = 6;    /** Signed 24 bit LPCM, big endian byte order */
+    public static final int SAMPLE_FORMAT_U24BE = 7;    /** Unsigned 24 bit LPCM, big endian byte order */
+    public static final int SAMPLE_FORMAT_S24LE = 8;    /** Signed 24 bit LPCM, little endian byte order */
+    public static final int SAMPLE_FORMAT_U24LE = 9;    /** Unsigned 24 bit LPCM, little endian byte order */
+    // FIXME: float formats (F32LE, F32BE)
+
+    // FIXME: add properties; sample size, sample playbackRate, duration, etc...
+
+    /**
+     * Load an audio clip from the specified source URI. Currently supported formats
+     * are AIFF and WAV files. Audio data in the file must be raw PCM, loading
+     * compressed files is not supported at this time.
+     *
+     * @param source URI to the desired clip.
+     * @return AudioClip ready to play.
+     * @throws IOException If an error occurred while loading the clip.
+     * @throws IllegalArgumentException If an invalid URI is provided.
+     */
+    public static AudioClip load(URI source) throws URISyntaxException, FileNotFoundException, IOException {
+        return AudioClipProvider.getProvider().load(source);
+    }
+
+    /**
+     * Generate a AudioClip from raw LPCM audio data. This can be used to
+     * programmatically create sound effects, either generated mathematically
+     * or loaded from some arbitrary source. Multiple channels must be
+     * interleaved properly, for stereo audio left channel is always first.
+     *
+     * @param data Raw PCM samples stored in a byte array.
+     * @param dataOffset Byte offset into data that the sample data starts.
+     * @param sampleCount Number of LPCM samples stored in data.
+     * @param sampleFormat Raw format that the LPCM data is being provided in.
+     * This may not be the actual format stored internally.
+     * @param channels The number of channels. Currently only two channel
+     * audio is supported, channels beyond two are simply dropped.
+     * @param sampleRate Audio sample playbackRate of the raw LPCM data.
+     *
+     * @return A new AudioClip that can play the given raw LPCM audio data.
+     * @throws IllegalArgumentException If an AudioClip cannot be created with
+     * the given arguments.
+     */
+    public static AudioClip create(byte [] data, int dataOffset, int sampleCount, int sampleFormat, int channels, int sampleRate)
+            throws IllegalArgumentException
+    {
+        return AudioClipProvider.getProvider().create(data, dataOffset, sampleCount, sampleFormat, channels, sampleRate);
+    }
+
+    /**
+     * Stop all AudioClips that are currently playing.
+     */
+    public static void stopAllClips() {
+        AudioClipProvider.getProvider().stopAllClips();
+    }
+
+    /**
+     * Create a new AudioClip from a segment of an existing AudioClip. The new
+     * clip may copy or simply reference this existing clip, so be aware that
+     * this operation may have a severe memory usage impact for long segments.
+     * The default parameters are copied to the new clip. This variant specifies
+     * the start and end times of the segment. Specifying an end time beyond the
+     * duration of the clip will crop the new AudioClip to the end of the source
+     * clip. Specifying a start time less than zero or greater than end time is
+     * undefined and will return null.
+     *
+     * @param startTime The start time for the segment
+     * @param stopTime The end time of the segment or -1.0 for the remainder of
+     * the source clip.
+     *
+     * @return A new AudioClip instance containing only the specified segment of
+     * the source clip
+     * @throws IllegalArgumentException If startTime or stopTime are not valid
+     * for this AudioClip.
+     */
+    public abstract AudioClip createSegment(double startTime, double stopTime) throws IllegalArgumentException;
+
+    /**
+     * Create a new AudioClip from a segment of an existing AudioClip. The new
+     * clip may copy or simply reference this existing clip, so be aware that
+     * this operation may have a severe memory usage impact for long segments.
+     * The default parameters are copied to the new clip. This variant specifies
+     * the exact sample offsets of the segment, starting at sample zero. If
+     * endSample is greater than the number of samples in the source clip, it
+     * will be cropped to the last sample. Specifying a start sample less than
+     * zero or higher than endSample is undefined and will return null.
+     *
+     * @param startSample The starting audio sample for the segment
+     * @param endSample The ending audio sample of the segment, or -1 for the
+     * remainder of the source clip.
+     *
+     * @return A new AudioClip instance containing only the specified segment of
+     * the source clip
+     * @throws IllegalArgumentException If the given sample range is invalid for
+     * this AudioClip.
+     */
+    public abstract AudioClip createSegment(int startSample, int endSample) throws IllegalArgumentException;
+
+    /**
+     * Create a new AudioClip from an existing clip by resampling a segment of
+     * the source clip to the specified sample playbackRate.
+     *
+     * @param startSample starting sample to begin resampling at. The first
+     * sample is always zero, negative values are not allowed.
+     * @param endSample The last sample to resample or -1 for the remainder of
+     * the source clip.
+     * @param newSampleRate The sample playbackRate to create the new AudioClip at.
+     *
+     * @return A new AudioClip that contains a copy of the source AudioClip
+     * resampled to the new sample playbackRate.
+     * @throws IllegalArgumentException If the sample range is invalid for this
+     * AudioClip, or the new sample rate is not supported.
+     * @throws IOException If an error occurred during rate conversion.
+     */
+    public abstract AudioClip resample(int startSample, int endSample, int newSampleRate)
+            throws IllegalArgumentException, IOException;
+
+    /**
+     * Create a new AudioClip by appending the given clip to the current clip.
+     * The new clip is independent of the two source clips. If the sample rates
+     * are mismatched, the new clip will contain at least one resampled copy of
+     * a source clip. Which clip is resampled is implementation dependent.
+     *
+     * @param clip The clip to be appended to the current clip.
+     *
+     * @return A new AudioClip that contains the concatenation of the two source
+     * clips.
+     * @throws IOException If an error occurred during the concatenation,
+     * generally during rate conversion if it's necessary.
+     */
+    public abstract AudioClip append(AudioClip clip)
+            throws IOException;
+
+    /**
+     * Creates a completely independent AudioClip. Any references contained
+     * will be copied and the references removed. The result will be a single
+     * AudioEffect containing all the audio data required to produce the effect.
+     * If the effect is already independent, then this will simply return the
+     * same AudioClip.
+     *
+     * @return A new AudioClip that is independent of all other clips.
+     */
+    public abstract AudioClip flatten();
+
+    public int priority() {
+        return this.clipPriority;
+    }
+    public void setPriority(int prio) {
+        this.clipPriority = prio;
+    }
+
+    /**
+     * Get the number of times the associated AudioClip will repeat when
+     * played. Note that if you start a clip looping indefinitely the only way
+     * to stop is to call AudioClip.stop() to stop all playback of a clip.
+     *
+     * @return The number of times a AudioClip will be repeated when played.
+     */
+    public int loopCount() {
+        return this.loopCount;
+    }
+
+    /**
+     * Specify the number of times a AudioClip should be repeated when this
+     * player is played. Note that if you start a clip looping indefinitely
+     * the only way to stop is to call AudioClip.stop() to stop all playback of
+     * a clip.
+     *
+     * @param loopCount How many times to repeat the AudioClip during normal
+     * playback. If this is zero, then the AudioClip will play exactly once
+     * and stop. Set this to -1 to repeat indefinitely, other negative values
+     * are undefined.
+     */
+    public void setLoopCount(int loopCount) {
+        this.loopCount = loopCount;
+    }
+
+    /**
+     * Returns playback volume.
+     *
+     * @return Volume level.
+     */
+    public double volume() {
+        return this.clipVolume;
+    }
+
+    /**
+     * Set the volume level for playback. Volume control is by attenuation,
+     * a volume of 1.0 is full volume where 0.0 is effectively muted.
+     *
+     * @param volume
+     */
+    public void setVolume(double vol) {
+        this.clipVolume = vol;
+    }
+
+    /**
+     * Returns the left/right channel balance.
+     *
+     * @return
+     */
+    public double balance() {
+        return this.clipBalance;
+    }
+
+    /**
+     * Set left/right balance or relative channel volumes for stereo effects. A
+     * value of 0.0 is equal levels (both channels at full volume), -1.0 is full
+     * left channel with muted right, 1.0 is full right channel with muted left.
+     * @param balance Balance value.
+     */
+    public void setBalance(double bal) {
+        this.clipBalance = bal;
+    }
+
+    /**
+     * Gets the audio sample rate multiplier that this player will use while
+     * playing the associated AudioClip.
+     *
+     * @return Audio playback sample rate multiplier.
+     *
+     * @see #setPlaybackRate(double)
+     */
+    public double playbackRate() {
+        return this.clipRate;
+    }
+
+    /**
+     * Set the audio sample rate multiplier. The player will use this multiplier
+     * when mixing audio to effectively modify the playback rate. A value of 1.0
+     * plays the AudioClip at it's normal sample rate. For example, setting
+     * the playback rate of a AudioClip that normally plays at 48 KHz to 0.5
+     * will cause the player to effectively play the AudioClip at 24 KHz.
+     *
+     * @param rate The new audio rate multiplier. Only positive values above
+     * zero are allowed. Note that implementations may cap this value at some
+     * undefined amount.
+     *
+     * @see #playbackRate()
+     */
+    public void setPlaybackRate(double rate) {
+        this.clipRate = rate;
+    }
+
+    /**
+     * Pan (left/right spread) setting.
+     *
+     * @return Current pan value.
+     */
+    public double pan() {
+        return this.clipPan;
+    }
+
+    /**
+     * Sets the audio pan (or left/right channel spread) value. Valid range is
+     * -1.0 to 1.0 inclusively. A zero setting means normal playback, left and
+     * right channels will be sent to their respective output channels. A -1.0
+     * value shifts the AudioClip so that all sound is output only on the left
+     * output channel, likewise a 1.0 value shifts completely to the right
+     * output channel.
+     *
+     * @param pan Audio pan setting
+     */
+    public void setPan(double pan) {
+        this.clipPan = pan;
+    }
+
+    /**
+     * Test if any AudioClipPlayer has this AudioClip in its effect chain.
+     *
+     * @return true if at least one AudioClipPlayer is playing or
+     * has this AudioClip enqueued.
+     */
+    public abstract boolean isPlaying();
+
+    /**
+     * Play this AudioClip with the default parameters. This is a fire and
+     * forget method, the clip will play exactly once using the default
+     * parameters.
+     */
+    public abstract void play();
+
+    /**
+     * Play this AudioClip at the given volume level. This is a fire and
+     * forget method, the clip will play exactly once using the given volume and
+     * default pitch and pan.
+     *
+     * @param volume Volume level to play this effect at. Valid volume range is
+     * 0.0 to 1.0, where 0.0 is effectively muted and 1.0 is full volume.
+     */
+    public abstract void play(double volume);
+
+    /**
+     * Play this AudioClip at the given volume level and relative pitch. This is
+     * a fire and forget method, the clip will play exactly once using the given
+     * parameters.
+     *
+     * @param volume Volume level to play this effect at. Valid volume range is
+     * 0.0 to 1.0, where 0.0 is effectively muted and 1.0 is full volume.
+     * @param balance Left/right balance or relative channel volumes for stereo
+     * effects.
+     * @param rate Playback rate multiplier. 1.0 will play back at the normal
+     * rate while 2.0 will double the rate.
+     * @param pan Left/right shift to be applied to the clip. A pan value of
+     * -1.0 means full left channel, 1.0 means full right channel, 0.0 has no
+     * effect.
+     * @param loopCount The number of times to play this clip, specify -1 to
+     * loop indefinitely
+     * @param priority Audio effect priority. Lower priority effects will be
+     * dropped first if too many effects are trying to play simultaneously.
+     */
+    public abstract void play(double volume, double balance, double rate, double pan, int loopCount, int priority);
+
+    /**
+     * Stops all playback of this AudioClip.
+     */
+    public abstract void stop();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/Media.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.ArrayList;
+import java.util.List;
+import com.sun.media.jfxmedia.locator.Locator;
+import com.sun.media.jfxmedia.track.Track;
+
+/**
+ * A class representing a particular media.
+ *
+ * @see MediaManager
+ * @see MediaPlayer
+ */
+public abstract class Media {
+
+    private Locator locator;
+    private final List<Track> tracks = new ArrayList<Track>();
+
+    /**
+     * Create a <code>Media</code> object.
+     *
+     * @param locator <code>Locator</code> of the <code>Media</code>
+     * @throws <code>IllegalArgumentException</code> if <code>locator</code>
+     * is <code>null</code>.
+     */
+    protected Media(Locator locator) {
+        if (locator == null) {
+            throw new IllegalArgumentException("locator == null!");
+        }
+
+        this.locator = locator;
+    }
+
+    /**
+     * Adds a marker to the media playback.  This marker will not be as precise
+     * as embedded markers in the media file.
+     *
+     * @param markerName        Arbitrary name of the marker
+     * @param presentationTime  Presentation time for the marker
+     * @throws <code>IllegalArgumentException</code> if <code>markerName</code>
+     * is <code>null</code> or <code>presentationTime</code> is negative.
+     */
+    public abstract void addMarker(String markerName, double presentationTime);
+
+    /**
+     * Removes a marker by name.
+     *
+     * @param markerName    Name of the marker
+     * @return The presentation time of the deleted marker.
+     * @throws <code>IllegalArgumentException</code> if <code>markerName</code>
+     * is <code>null</code>.
+     */
+    public abstract double removeMarker(String markerName);
+
+    /**
+     * Removes all markers, added programmatically, from the media playback.
+     * Embedded markers will still cause notifications to fire.
+     */
+    public abstract void removeAllMarkers();
+
+    /**
+     * Gets the tracks found in the media. The returned value will be
+     * <code>null</code> if no tracks have yet been encountered while scanning
+     * the media. The returned <code>List</code> us unmodifiable.
+     *
+     * @return the tracks in the media or <code>null</code> if no tracks found.
+     */
+    public List<Track> getTracks() {
+        List<Track> returnValue;
+        synchronized(tracks) {
+            if (tracks.isEmpty()) {
+                returnValue = null;
+            } else {
+                returnValue = Collections.unmodifiableList(new ArrayList<Track>(tracks));
+            }
+        }
+        return returnValue;
+    }
+
+    /**
+     * Get the markers of the media. The returned
+     * <code>Map</code> is unmodifiable.
+     *
+     * @return the markers or <code>null</code> if no markers found.
+     */
+    public abstract Map<String, Double> getMarkers();
+
+    /**
+     * Gets the <code>Locator</code> which was the source of the media.
+     *
+     * @return the source <code>Locator</code>.
+     */
+    public Locator getLocator() {
+        return locator;
+    }
+
+    /**
+     * Adds a <code>Track</code>.
+     * @throws <code>IllegalArgumentException</code> if <code>track</code> is
+     * <code>null</code>.
+     */
+    protected void addTrack(Track track) {
+        if (track == null) {
+            throw new IllegalArgumentException("track == null!");
+        }
+        synchronized(tracks) {
+            this.tracks.add(track);
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuffer buffer = new StringBuffer();
+
+        if(tracks != null && !tracks.isEmpty()) {
+            for(Track track : tracks) {
+                buffer.append(track);
+                buffer.append("\n");
+            }
+        }
+
+        return buffer.toString();
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/MediaError.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia;
+
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+
+public enum MediaError {
+
+    ERROR_BASE_MEDIA(0x00000100),
+    ERROR_BASE_MANAGER(0x00000200),
+    ERROR_BASE_PIPELINE(0x00000300),
+    ERROR_BASE_FACTORY(0x00000400),
+    ERROR_BASE_LOCATOR(0x00000500),
+    ERROR_BASE_REGISTRY(0x00000600),
+    ERROR_BASE_GSTREAMER(0x00000800),
+    ERROR_BASE_SYSTEM(0x00000A00),
+    ERROR_BASE_FUNCTION(0x00000B00),
+    ERROR_BASE_JNI(0x00000C00),       // JNI upcall from native into Java
+    ERROR_BASE_OSX(0x00000D00),
+
+    WARNING_BASE_JFXMEDIA(0x00100000),
+    WARNING_BASE_GSTREAMER(0x00800000),
+    WARNING_BASE_GLIB(0x00900000),
+
+    ERROR_MASK_BASE(0x00000F00),
+    WARNING_MASK_BASE(0x00F00000),
+
+    ERROR_NONE(0x0),
+
+    ERROR_MANAGER_NULL(ERROR_BASE_MANAGER.code()+0x0001),
+    ERROR_MANAGER_CREATION(ERROR_BASE_MANAGER.code()+0x0002),
+    ERROR_MANAGER_ENGINEINIT_FAIL(ERROR_BASE_MANAGER.code()+0x0003),
+    ERROR_MANAGER_RUNLOOP_FAIL(ERROR_BASE_MANAGER.code()+0x0004),
+    ERROR_MANAGER_LOGGER_INIT(ERROR_BASE_MANAGER.code()+0x0005),
+
+    ERROR_MEDIA_NULL(ERROR_BASE_MEDIA.code()+0x0001),
+    ERROR_MEDIA_CREATION(ERROR_BASE_MEDIA.code()+0x0002),
+    ERROR_MEDIA_UNKNOWN_PIXEL_FORMAT(ERROR_BASE_MEDIA.code()+0x0003),
+    ERROR_MEDIA_INVALID(ERROR_BASE_MEDIA.code()+0x0004),
+    ERROR_MEDIA_MARKER_NAME_NULL(ERROR_BASE_MEDIA.code()+0x0005),
+    ERROR_MEDIA_MARKER_TIME_NEGATIVE(ERROR_BASE_MEDIA.code()+0x0006),
+    ERROR_MEDIA_MARKER_MAP_NULL(ERROR_BASE_MEDIA.code()+0x0007),
+    ERROR_MEDIA_VIDEO_FORMAT_UNSUPPORTED(ERROR_BASE_MEDIA.code()+0x0008),
+    ERROR_MEDIA_AUDIO_FORMAT_UNSUPPORTED(ERROR_BASE_MEDIA.code()+0x0009),
+    ERROR_MEDIA_MP3_FORMAT_UNSUPPORTED(ERROR_BASE_MEDIA.code()+0x000A),
+    ERROR_MEDIA_AAC_FORMAT_UNSUPPORTED(ERROR_BASE_MEDIA.code()+0x000B),
+    ERROR_MEDIA_H264_FORMAT_UNSUPPORTED(ERROR_BASE_MEDIA.code()+0x000C),
+    ERROR_MEDIA_HLS_FORMAT_UNSUPPORTED(ERROR_BASE_MEDIA.code()+0x000D),
+    ERROR_MEDIA_CORRUPTED(ERROR_BASE_MEDIA.code()+0x000E),
+
+    ERROR_PIPELINE_NULL(ERROR_BASE_PIPELINE.code()+0x0001),
+    ERROR_PIPELINE_CREATION(ERROR_BASE_PIPELINE.code()+0x0002),
+    ERROR_PIPELINE_NO_FRAME_QUEUE(ERROR_BASE_PIPELINE.code()+0x0003),
+
+    ERROR_FACTORY_NULL(ERROR_BASE_FACTORY.code()+0x0001),
+    ERROR_FACTORY_CONTAINER_CREATION(ERROR_BASE_FACTORY.code()+0x0002),
+    ERROR_FACTORY_INVALID_URI(ERROR_BASE_FACTORY.code()+0x0003),
+
+    ERROR_LOCATOR_NULL(ERROR_BASE_LOCATOR.code()+0x0001),
+    ERROR_LOCATOR_UNSUPPORTED_TYPE(ERROR_BASE_LOCATOR.code()+0x0002),
+    ERROR_LOCATOR_UNSUPPORTED_MEDIA_FORMAT(ERROR_BASE_LOCATOR.code()+0x0003),
+    ERROR_LOCATOR_CONNECTION_LOST(ERROR_BASE_LOCATOR.code()+0x0004),
+    ERROR_LOCATOR_CONTENT_TYPE_NULL(ERROR_BASE_LOCATOR.code()+0x0005),
+
+    ERROR_REGISTRY_NULL(ERROR_BASE_REGISTRY.code()+0x0001),
+    ERROR_REGISTRY_PLUGIN_ALREADY_EXIST(ERROR_BASE_REGISTRY.code()+0x0002),
+    ERROR_REGISTRY_PLUGIN_PATH(ERROR_BASE_REGISTRY.code()+0x0003),
+    ERROR_REGISTRY_NO_MATCHING_RECIPE(ERROR_BASE_REGISTRY.code()+0x0004),
+
+    ERROR_GSTREAMER_ERROR(ERROR_BASE_GSTREAMER.code()+0x0001),
+    ERROR_GSTREAMER_PIPELINE_CREATION(ERROR_BASE_GSTREAMER.code()+0x0002),
+    ERROR_GSTREAMER_AUDIO_DECODER_SINK_PAD(ERROR_BASE_GSTREAMER.code()+0x0003),
+    ERROR_GSTREAMER_AUDIO_DECODER_SRC_PAD(ERROR_BASE_GSTREAMER.code()+0x0004),
+    ERROR_GSTREAMER_AUDIO_SINK_SINK_PAD(ERROR_BASE_GSTREAMER.code()+0x0005),
+    ERROR_GSTREAMER_VIDEO_DECODER_SINK_PAD(ERROR_BASE_GSTREAMER.code()+0x0006),
+    ERROR_GSTREAMER_PIPELINE_STATE_CHANGE(ERROR_BASE_GSTREAMER.code()+0x0007),
+    ERROR_GSTREAMER_PIPELINE_SEEK(ERROR_BASE_GSTREAMER.code()+0x0008),
+    ERROR_GSTREAMER_PIPELINE_QUERY_LENGTH(ERROR_BASE_GSTREAMER.code()+0x0009),
+    ERROR_GSTREAMER_PIPELINE_QUERY_POS(ERROR_BASE_GSTREAMER.code()+0x000A),
+    ERROR_GSTREAMER_PIPELINE_METADATA_TYPE(ERROR_BASE_GSTREAMER.code()+0x000B),
+    ERROR_GSTREAMER_AUDIO_SINK_CREATE(ERROR_BASE_GSTREAMER.code()+0x000C),
+    ERROR_GSTREAMER_GET_BUFFER_SRC_PAD(ERROR_BASE_GSTREAMER.code()+0x000D),
+    ERROR_GSTREAMER_CREATE_GHOST_PAD(ERROR_BASE_GSTREAMER.code()+0x000E),
+    ERROR_GSTREAMER_ELEMENT_ADD_PAD(ERROR_BASE_GSTREAMER.code()+0x000F),
+    ERROR_GSTREAMER_UNSUPPORTED_PROTOCOL(ERROR_BASE_GSTREAMER.code()+0x0010),
+    ERROR_GSTREAMER_SOURCEFILE_NONEXISTENT(ERROR_BASE_GSTREAMER.code()+0x0020),
+    ERROR_GSTREAMER_SOURCEFILE_NONREGULAR(ERROR_BASE_GSTREAMER.code()+0x0030),
+    ERROR_GSTREAMER_ELEMENT_LINK(ERROR_BASE_GSTREAMER.code()+0x0040),
+    ERROR_GSTREAMER_ELEMENT_LINK_AUDIO_BIN(ERROR_BASE_GSTREAMER.code()+0x0050),
+    ERROR_GSTREAMER_ELEMENT_LINK_VIDEO_BIN(ERROR_BASE_GSTREAMER.code()+0x0060),
+    ERROR_GSTREAMER_ELEMENT_CREATE(ERROR_BASE_GSTREAMER.code()+0x0070),
+    ERROR_GSTREAMER_VIDEO_SINK_CREATE(ERROR_BASE_GSTREAMER.code()+0x0080),
+    ERROR_GSTREAMER_BIN_CREATE(ERROR_BASE_GSTREAMER.code()+0x0090),
+    ERROR_GSTREAMER_BIN_ADD_ELEMENT(ERROR_BASE_GSTREAMER.code()+0x00A0),
+    ERROR_GSTREAMER_ELEMENT_GET_PAD(ERROR_BASE_GSTREAMER.code()+0x00B0),
+    ERROR_GSTREAMER_MAIN_LOOP_CREATE(ERROR_BASE_GSTREAMER.code()+0x00C0),
+    ERROR_GSTREAMER_BUS_SOURCE_ATTACH(ERROR_BASE_GSTREAMER.code()+0x00C1),
+    ERROR_GSTREAMER_PIPELINE_SET_RATE_ZERO(ERROR_BASE_GSTREAMER.code()+0x00D0),
+    ERROR_GSTREAMER_VIDEO_SINK_SINK_PAD(ERROR_BASE_GSTREAMER.code()+0x00E0),
+
+    ERROR_NOT_IMPLEMENTED(ERROR_BASE_SYSTEM.code()+0x0001),
+    ERROR_MEMORY_ALLOCATION(ERROR_BASE_SYSTEM.code()+0x0002),
+    ERROR_OS_UNSUPPORTED(ERROR_BASE_SYSTEM.code()+0x0003),
+    ERROR_PLATFORM_UNSUPPORTED(ERROR_BASE_SYSTEM.code()+0x0004),
+
+    ERROR_FUNCTION_PARAM(ERROR_BASE_FUNCTION.code()+0x0001),
+    ERROR_FUNCTION_PARAM_NULL(ERROR_BASE_FUNCTION.code()+0x0002),
+
+    ERROR_JNI_SEND_PLAYER_MEDIA_ERROR_EVENT(ERROR_BASE_JNI.code()+0x0001),
+    ERROR_JNI_SEND_PLAYER_HALT_EVENT(ERROR_BASE_JNI.code()+0x0002),
+    ERROR_JNI_SEND_PLAYER_STATE_EVENT(ERROR_BASE_JNI.code()+0x0003),
+    ERROR_JNI_SEND_NEW_FRAME_EVENT(ERROR_BASE_JNI.code()+0x0004),
+    ERROR_JNI_SEND_FRAME_SIZE_CHANGED_EVENT(ERROR_BASE_JNI.code()+0x0005),
+    ERROR_JNI_SEND_END_OF_MEDIA_EVENT(ERROR_BASE_JNI.code()+0x0006),
+    ERROR_JNI_SEND_AUDIO_TRACK_EVENT(ERROR_BASE_JNI.code()+0x0007),
+    ERROR_JNI_SEND_VIDEO_TRACK_EVENT(ERROR_BASE_JNI.code()+0x0008),
+    ERROR_JNI_SEND_METADATA_EVENT(ERROR_BASE_JNI.code()+0x0009),
+    ERROR_JNI_SEND_MARKER_EVENT(ERROR_BASE_JNI.code()+0x000A),
+    ERROR_JNI_SEND_BUFFER_PROGRESS_EVENT(ERROR_BASE_JNI.code()+0x000B),
+    ERROR_JNI_SEND_STOP_REACHED_EVENT(ERROR_BASE_JNI.code()+0x000C),
+    ERROR_JNI_SEND_DURATION_UPDATE_EVENT(ERROR_BASE_JNI.code()+0x000D),
+    ERROR_JNI_SEND_AUDIO_SPECTRUM_EVENT(ERROR_BASE_JNI.code()+0x000E),
+    
+    ERROR_OSX_INIT(ERROR_BASE_OSX.code() + 0x0001),
+    
+    WARNING_JFXMEDIA_BALANCE(WARNING_BASE_JFXMEDIA.code() + 0x0001),
+
+    WARNING_GSTREAMER_WARNING(WARNING_BASE_GSTREAMER.code()+0x0001),
+    WARNING_GSTREAMER_PIPELINE_ERROR(WARNING_BASE_GSTREAMER.code()+0x0002),
+    WARNING_GSTREAMER_PIPELINE_WARNING(WARNING_BASE_GSTREAMER.code()+0x0003),
+    WARNING_GSTREAMER_PIPELINE_STATE_EVENT(WARNING_BASE_GSTREAMER.code()+0x0004),
+    WARNING_GSTREAMER_PIPELINE_FRAME_SIZE(WARNING_BASE_GSTREAMER.code()+0x0005),
+    WARNING_GSTREAMER_INVALID_FRAME(WARNING_BASE_GSTREAMER.code()+0x0006),
+    WARNING_GSTREAMER_PIPELINE_INFO_ERROR(WARNING_BASE_GSTREAMER.code()+0x0007),
+    WARNING_GSTREAMER_AUDIO_BUFFER_FIELD(WARNING_BASE_GSTREAMER.code()+0x0008);
+
+    private static ResourceBundle bundle;
+    private static final Map<Integer, MediaError> map = new HashMap<Integer, MediaError>();
+
+    static {
+        try {
+            bundle = ResourceBundle.getBundle("MediaErrors", Locale.getDefault());
+        } catch(MissingResourceException e) {
+            bundle = null;
+        }
+
+        for (MediaError error : MediaError.values()) {
+            map.put(error.code(), error);
+        }
+    }
+
+    private int    code;
+    private String description;
+
+    private MediaError(int code) {
+        this.code = code;
+    }
+
+    public int code() {
+        return code;
+    }
+
+    public String description() {
+        if (description == null) {
+            String errorName = name();
+            if (bundle != null) {
+                try {
+                    description = bundle.getString(errorName);
+                } catch (MissingResourceException e) {
+                    description = errorName;
+                }
+            } else {
+                description = errorName;
+            }
+        }
+        return description;
+    }
+
+    public static MediaError getFromCode(int code) {
+        return map.get(code);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/MediaException.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia;
+
+/**
+ * Class of exceptions which might be thrown while processing media.
+ */
+public class MediaException extends RuntimeException {
+    // Suppress compilation warnings; 14 <=> JavaFX 1.4.
+    private static final long serialVersionUID = 14L;
+
+    private MediaError error = null;
+
+    /**
+     * Constructor which merely passes its parameter to the corresponding
+     * superclass constructor
+     * {@link RuntimeException#RuntimeException(java.lang.String)}.
+     *
+     * @param message The detail message.
+     */
+    public MediaException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructor which merely passes its parameters to the corresponding
+     * superclass constructor
+     * {@link RuntimeException#RuntimeException(java.lang.String, java.lang.Throwable)}.
+     *
+     * @param message The detail message.
+     * @param cause The cause.
+     */
+    public MediaException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Constructor which merely passes its parameters to the corresponding
+     * superclass constructor
+     * {@link RuntimeException#RuntimeException(java.lang.String, java.lang.Throwable)}.
+     *
+     * @param message The detail message.
+     * @param cause The cause.
+     * @param error The media error.
+     */
+    public MediaException(String message, Throwable cause, MediaError error) {
+        super(message, cause);
+        this.error = error;
+    }
+
+    public MediaError getMediaError() {
+        return error;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/MediaManager.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia;
+
+import com.sun.media.jfxmedia.events.MediaErrorListener;
+import com.sun.media.jfxmedia.locator.Locator;
+import com.sun.media.jfxmediaimpl.NativeMediaManager;
+import java.util.List;
+
+/**
+ * Factory class used to create media objects, players, and recorders, and to
+ * manage other global functionality.
+ *
+ * @see MediaPlayer
+ * @see MediaRecorder
+ */
+public class MediaManager {
+
+    private MediaManager() {
+        // prevent instantiation of this class
+    }
+
+    /**
+     * @return {@link String} array of supported content types.
+     */
+    public static String[] getSupportedContentTypes() {
+        return NativeMediaManager.getDefaultInstance().getSupportedContentTypes();
+    }
+
+    /**
+     * Whether a media source having the indicated content type may be
+     * played.
+     *
+     * @throws IllegalArgumentException if <code>contentType</code> is
+     * <code>null</code>.
+     */
+    public static boolean canPlayContentType (String contentType) {
+        if (contentType == null) {
+            throw new IllegalArgumentException("contentType == null!");
+        }
+        return NativeMediaManager.getDefaultInstance().canPlayContentType (contentType);
+    }
+
+
+    // XXX javadoc
+    public static MetadataParser getMetadataParser(Locator locator) {
+        if (locator == null) {
+            throw new IllegalArgumentException("locator == null!");
+        }
+        return NativeMediaManager.getDefaultInstance().getMetadataParser(locator);
+    }
+
+    /**
+     * Gets a Media object for the clip.  It cannot be played without attaching
+     * to a MediaPlayer.
+     *
+     * @param locator
+     * @return Media object
+     * @throws IllegalArgumentException if <code>locator</code> is
+     * <code>null</code>.
+     */
+    public static Media getMedia(Locator locator) {
+        if (locator == null) {
+            throw new IllegalArgumentException("locator == null!");
+        }
+        return NativeMediaManager.getDefaultInstance().getMedia(locator);
+    }
+
+    /**
+     * Get a player for the media locator
+     *
+     * @param locator
+     * @return MediaPlayer object
+     * @throws IllegalArgumentException if <code>locator</code> is
+     * <code>null</code>.
+     */
+    public static MediaPlayer getPlayer(Locator locator) {
+        if (locator == null) {
+            throw new IllegalArgumentException("locator == null!");
+        }
+        return NativeMediaManager.getDefaultInstance().getPlayer(locator);
+    }
+
+    /**
+     * Add a global listener for warnings. This listener will receive warnings
+     * which occur fall outside the context of a particular player or recorder.
+     *
+     * @param listener The listener to add.
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public static void addMediaErrorListener(MediaErrorListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener == null!");
+        }
+        NativeMediaManager.getDefaultInstance().addMediaErrorListener(listener);
+    }
+
+    /**
+     * Remove a global listener for warnings.
+     *
+     * @param listener The listener to remove.
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public static void removeMediaErrorListener(MediaErrorListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener == null!");
+        }
+        NativeMediaManager.getDefaultInstance().removeMediaErrorListener(listener);
+    }
+
+    /**
+     * This function will register MediaPlayer for disposing when obj parameter
+     * does not have any strong reference.
+     *
+     * @param obj - Object to watch for strong references
+     * @param player - MediaPlayer to dispose
+     */
+    public static void registerMediaPlayerForDispose(Object obj, MediaPlayer player) {
+        NativeMediaManager.registerMediaPlayerForDispose(obj, player);
+    }
+
+    /**
+     * Retrieve all un-disposed {@link MediaPlayer}s.
+     * @return a {@link List} of all un-disposed players or <code>null</code>.
+     */
+    public static List<MediaPlayer> getAllMediaPlayers() {
+        return NativeMediaManager.getDefaultInstance().getAllMediaPlayers();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/MediaPlayer.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia;
+
+import com.sun.media.jfxmedia.effects.AudioEqualizer;
+import com.sun.media.jfxmedia.events.PlayerStateListener;
+import com.sun.media.jfxmedia.events.VideoTrackSizeListener;
+import com.sun.media.jfxmedia.control.VideoRenderControl;
+import com.sun.media.jfxmedia.effects.AudioSpectrum;
+import com.sun.media.jfxmedia.events.AudioSpectrumListener;
+import com.sun.media.jfxmedia.events.MarkerListener;
+import com.sun.media.jfxmedia.events.MediaErrorListener;
+import com.sun.media.jfxmedia.events.BufferListener;
+import com.sun.media.jfxmedia.events.PlayerStateEvent.PlayerState;
+import com.sun.media.jfxmedia.events.PlayerTimeListener;
+
+/**
+ * MediaPlayer class provides control of media playback.  Get a MediaPlayer from
+ * either MediaManager or MediaRecorder.
+ *
+ * @see MediaManager
+ * @see MediaRecorder
+ */
+public interface MediaPlayer {
+    //**************************************************************************
+    //***** Public control functions
+    //**************************************************************************
+
+    /**
+     * Adds a listener for warnings which occur within the lifespan of the player.
+     *
+     * @param listener The warning listener.
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public void addMediaErrorListener(MediaErrorListener listener);
+
+    /**
+     * Removes a listener for warnings.
+     *
+     * @param listener The warning listener.
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public void removeMediaErrorListener(MediaErrorListener listener);
+
+    /**
+     * Adds a listener for media state.
+     *
+     * @param listener
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public void addMediaPlayerListener(PlayerStateListener listener);
+
+    /**
+     * Removes a listener for media state.
+     *
+     * @param listener
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public void removeMediaPlayerListener(PlayerStateListener listener);
+
+    /**
+     * Adds a listener for player time events.
+     *
+     * @param listener
+     */
+    public void addMediaTimeListener(PlayerTimeListener listener);
+
+    /**
+     * Removes a listener for player time events.
+     *
+     * @param listener
+     */
+    public void removeMediaTimeListener(PlayerTimeListener listener);
+
+    /**
+     * Adds a listener for video track frame dimensions.
+     *
+     * @param listener
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public void addVideoTrackSizeListener(VideoTrackSizeListener listener);
+
+    /**
+     * Removes a listener for video track frame dimensions.
+     *
+     * @param listener
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public void removeVideoTrackSizeListener(VideoTrackSizeListener listener);
+
+    /**
+     * Adds a listener for marker events.
+     *
+     * @param listener
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public void addMarkerListener(MarkerListener listener);
+
+    /**
+     * Removes a listener for marker events.
+     *
+     * @param listener
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public void removeMarkerListener(MarkerListener listener);
+
+    /**
+     * Adds a listener for all buffer events.
+     *
+     * @param listener
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public void addBufferListener(BufferListener listener);
+
+    /**
+     * Removes a listener for buffer events.
+     *
+     * @param listener
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public void removeBufferListener(BufferListener listener);
+
+     /**
+     * Adds a listener for audio spectrum events.
+     *
+     * @param listener
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public void addAudioSpectrumListener(AudioSpectrumListener listener);
+
+    /**
+     * Removes a listener for audio spectrum events.
+     *
+     * @param listener
+     * @throws IllegalArgumentException if <code>listener</code> is
+     * <code>null</code>.
+     */
+    public void removeAudioSpectrumListener(AudioSpectrumListener listener);
+
+    /**
+     * Returns the video rendering support interface.
+     *
+     * @return A <code>VideoRenderControl</code> instance.
+     */
+    public VideoRenderControl getVideoRenderControl();
+
+    /**
+     * Gets a Media object.
+     *
+     * @return Media object.
+     */
+    public Media getMedia();
+
+    /**
+     * Set the amount of time to delay the audio. A positive value makes audio
+     * render later, and a negative value makes audio render earlier.
+     *
+     * @param delay time in milliseconds
+     */
+    public void setAudioSyncDelay(long delay);
+
+    /**
+     * Retrieve the audio rendering delay.
+     */
+    public long getAudioSyncDelay();
+
+    /**
+     * Begins playing of the media.  To ensure smooth playback, catch the
+     * onReady event in the MediaPlayerListener before playing.
+     */
+    public void play();
+
+    /**
+     * Stops playing of the media and resets the play time to 0.
+     */
+    public void stop();
+
+    /**
+     * Pauses the media playing.  Calling play() after pause() will continue
+     * playing the media from where it left off.
+     */
+    public void pause();
+
+    /**
+     * Get the rate of playback.
+     */
+    public float getRate();
+
+    //**************************************************************************
+    //***** Public properties
+    //**************************************************************************
+    /**
+     * Sets the rate of playback. A positive value indicates forward play and
+     * a negative value reverse play.
+     *
+     * @param rate
+     */
+    public void setRate(float rate);
+
+    /**
+     * Gets the current presentation time. If the time is unknown or cannot be
+     * obtained when this method is invoked, a negative value will be returned.
+     *
+     * @return the current presentation time
+     */
+    public double getPresentationTime();
+
+    /**
+     * Gets the current volume.
+     *
+     * @return the current volume
+     */
+    public float getVolume();
+
+    /**
+     * Sets the volume. Values will be clamped to the range
+     * <code>[0,&nbsp;1.0]</code>.
+     *
+     * @param volume A value in the range <code>[0,&nbsp;1.0]</code>.
+     */
+    public void setVolume(float volume);
+
+    /**
+     * Gets the muted state. While muted no audio will be heard.
+     * @return true if audio is muted.
+     */
+    public boolean getMute();
+
+    /**
+     * Enables/disable mute.  If mute is enabled then disabled, the previous
+     * volume goes into effect.
+     */
+    public void setMute(boolean enable);
+
+    /**
+     * Gets the current balance.
+     *
+     * @return the current balance
+     */
+    public float getBalance();
+
+    /**
+     * Sets the balance. A negative value indicates left of center and a positive
+     * value right of center. Values will be clamped to the range
+     * <code>[-1.0,&nbsp;1.0]</code>.
+     *
+     * @param balance A value in the range <code>[-1.0,&nbsp;1.0]</code>.
+     */
+    public void setBalance(float balance);
+
+    /**
+     * Gets the master audio equalizer for the player.
+     *
+     * @return AudioEqualizer object
+     */
+    public AudioEqualizer getEqualizer();
+
+    /**
+     * Gets the audio spectrum controller for the player.
+     *
+     * @return AudioSpectrum object
+     */
+    public AudioSpectrum getAudioSpectrum();
+
+    /**
+     * Gets the duration in seconds. If the duration is unknown or cannot be
+     * obtained when this method is invoked, a negative value will be returned.
+     */
+    public double getDuration();
+
+    /**
+     * Gets the time within the duration of the media to start playing.
+     */
+    public double getStartTime();
+
+    /**
+     * Sets the start time within the media to play.
+     */
+    public void setStartTime(double streamTime);
+
+    /**
+     * Gets the time within the duration of the media to stop playing.
+     */
+    public double getStopTime();
+
+    /**
+     * Sets the stop time within the media to stop playback.
+     */
+    public void setStopTime(double streamTime);
+
+    /**
+     * Seeks playback to the specified time. The state of the player
+     * is unchanged. A negative value will be clamped to zero, and a positive
+     * value to the duration, if known.
+     *
+     * @param streamTime The time in seconds to which to seek.
+     */
+    public void seek(double streamTime);
+
+    /**
+     * Retrieves the current {@link PlayerState state} of the player.
+     * @return the current player state.
+     */
+    public PlayerState getState();
+    /**
+     * Release any resources held by this player. The player will be unusable
+     * after this method is invoked.
+     */
+    public void dispose();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/MetadataParser.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia;
+
+import com.sun.media.jfxmedia.events.MetadataListener;
+import java.io.IOException;
+
+public interface MetadataParser {
+    // FLV and MP3
+    static final String DURATION_TAG_NAME = "duration";
+    // FLV
+    static final String CREATIONDATE_TAG_NAME = "creationdate";
+    static final String WIDTH_TAG_NAME = "width";
+    static final String HEIGHT_TAG_NAME = "height";
+    static final String FRAMERATE_TAG_NAME = "framerate";
+    static final String VIDEOCODEC_TAG_NAME = "video codec";
+    static final String AUDIOCODEC_TAG_NAME = "audio codec";
+    // MP3
+    static final String IMAGE_TAG_NAME = "image";
+    static final String ALBUMARTIST_TAG_NAME = "album artist";
+    static final String ALBUM_TAG_NAME = "album";
+    static final String ARTIST_TAG_NAME = "artist";
+    static final String COMMENT_TAG_NAME = "comment";
+    static final String COMPOSER_TAG_NAME = "composer";
+    static final String GENRE_TAG_NAME = "genre";
+    static final String TITLE_TAG_NAME = "title";
+    static final String TRACKNUMBER_TAG_NAME = "track number";
+    static final String TRACKCOUNT_TAG_NAME = "track count";
+    static final String DISCNUMBER_TAG_NAME = "disc number";
+    static final String DISCCOUNT_TAG_NAME = "disc count";
+    static final String YEAR_TAG_NAME = "year";
+    static final String TEXT_TAG_NAME = "text";
+
+    static final String RAW_METADATA_TAG_NAME = "raw metadata";
+    static final String RAW_FLV_METADATA_NAME = "FLV";
+    static final String RAW_ID3_METADATA_NAME = "ID3";
+
+    void addListener(MetadataListener listener);
+
+    void removeListener(MetadataListener listener);
+
+    void startParser() throws IOException;
+
+    void stopParser();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/control/VideoDataBuffer.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.control;
+
+import java.nio.ByteBuffer;
+
+/**
+ * A (@code VideoDataBuffer} describes a single uncompressed frame of video.
+ */
+public interface VideoDataBuffer {
+    /** Plane index used by all packed formats */
+    public static final int PACKED_FORMAT_PLANE = 0;
+
+    /** Plane index for YCbCr luminance data */
+    public static final int YCBCR_PLANE_LUMA = 0;
+    /** Plane index for YCbCr red chrominance data */
+    public static final int YCBCR_PLANE_CR = 1;
+    /** Plane index for YCbCr blue chrominance data */
+    public static final int YCBCR_PLANE_CB = 2;
+    /** Plane index for YCbCr alpha data, this plane is optional */
+    public static final int YCBCR_PLANE_ALPHA = 3;
+
+    /**
+     * Retrieve the data buffer containing video data
+     *
+     * @return The media buffer's data.
+     */
+    public ByteBuffer getBuffer();
+
+    /**
+     * Retrieve the timestamp of the buffer.
+     *
+     * @return The buffer's timestamp.
+     */
+    public double getTimestamp();
+
+    /**
+     * Retrieves the frame number of this video frame.
+     *
+     * FIXME: Nuke this, it's completely unused and not useful anyways
+     *
+     * @return The frame's number
+     */
+    public long getFrameNumber();
+
+    /**
+     * Gets the width of the VideoDataBuffer
+     * @return the width of the buffer
+     */
+    public int getWidth();
+
+    /**
+     * Gets the height of the VideoDataBuffer
+     * @return the height
+     */
+    public int getHeight();
+
+    /**
+     * Gets the width of the image as created by the decoder, this may be larger
+     * than the display width.
+     * @return the number of pixels per row in the image
+     */
+    public int getEncodedWidth();
+
+    /**
+     * Gets the height of the image as created by the decoder, this may be larger
+     * than the display height.
+     * @return the number of rows in the image
+     */
+    public int getEncodedHeight();
+
+    /**
+     * Gets the format of the videoDataBuffer
+     */
+    public VideoFormat getFormat();
+
+    /**
+     * Determine if a video buffer has an alpha channel. This merely determines
+     * if the buffer itself has an alpha channel, not if there is any transparency
+     * to the image.
+     *
+     * @return true if an alpha channel is present
+     */
+    public boolean hasAlpha();
+
+    /**
+     * Gets the number of bit planes this video image contains. Non planar formats
+     * will always return 1.
+     */
+    public int getPlaneCount();
+
+    /**
+     * Returns the byte offset to the specified bit plane.
+     *
+     * @param planeIndex The numeric index of the plane.
+     * @return Number of bytes from the beginning of data that the specified
+     * plane starts at. Will return zero if the plane is not in use.
+     */
+    public int getOffsetForPlane(int planeIndex);
+
+    public int[] getPlaneOffsets();
+
+    /**
+     * Returns the number of bytes in each row of pixels for the specified plane.
+     *
+     * @param planeIndex The numeric index of the plane.
+     * @return Number of bytes that comprises a single row of pixels in the
+     * specified plane. Will return zero if the plane is not in use.
+     */
+    public int getStrideForPlane(int planeIndex);
+
+    public int[] getPlaneStrides();
+
+    /**
+     * Converts the video image to the specified format. You can only convert TO
+     * either {@code ARGB_PRE} or {@code BGRA_PRE}, converting to YCbCr is not
+     * supported here. Once a conversion is done, a reference to the converted
+     * buffer is retained so that future conversions do not need to be performed.
+     *
+     * @return new buffer containing a converted copy of the source video image
+     */
+    public VideoDataBuffer convertToFormat(VideoFormat newFormat);
+
+    /**
+     * Flags a video buffer indicating the contents of the buffer have been
+     * updated and any cached representations need to be updated.
+     */
+    public void setDirty();
+
+    /**
+     * Place a hold on a buffer so that it cannot be reused by the buffer pool
+     * from whence it came. Holding a buffer too long may cause additional
+     * buffers to be allocated which will increase memory usage, so one should
+     * take care to release a frame as soon as possible.
+     */
+    public void holdFrame();
+
+    /**
+     * Releases a hold previously placed on this frame. When the hold count
+     * reaches zero then the frame will be disposed or reused, thus preventing
+     * memory allocation overhead.
+     */
+    public void releaseFrame();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/control/VideoFormat.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.control;
+
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.Map;
+
+public enum VideoFormat {
+    /** Packed ARGB, in memory A,R,G,B alpha is NOT pre-multiplied.
+     *  This is synonymous with BYTE_ARGB */
+    ARGB(FormatTypes.FORMAT_TYPE_ARGB),
+    /** Packed BGRA, in memory B,G,R,A alpha is pre-multiplied.
+     *  This format is synonymous with BYTE_BGRA_PRE or little endian INT_ARGB_PRE */
+    BGRA_PRE(FormatTypes.FORMAT_TYPE_BGRA_PRE),
+    /** Planar YCbCr 4:2:0, alpha channel is optional. The presence of a fourth
+     *  plane indicates alpha is present */
+    YCbCr_420p(FormatTypes.FORMAT_TYPE_YCBCR_420P),
+    /** Packed YCbCr 4:2:2, no alpha support (Only used on Mac currently). This
+     *  format is synonymous with the 'yuvs' pixel format in QuickTime (tm) */
+    YCbCr_422(FormatTypes.FORMAT_TYPE_YCBCR_422);
+
+    private int nativeType; // value passed down to native code to represent this format
+    private static final Map<Integer, VideoFormat> lookupMap = new HashMap<Integer, VideoFormat>();
+    static {
+        for (VideoFormat fmt : EnumSet.allOf(VideoFormat.class)) {
+            lookupMap.put(fmt.getNativeType(), fmt);
+        }
+    }
+
+    private VideoFormat(int ntype) {
+        nativeType = ntype;
+    }
+
+    public int getNativeType() {
+        return nativeType;
+    }
+
+    public boolean isRGB() {
+        return this == ARGB || this == BGRA_PRE;
+    }
+
+    public boolean isEqualTo(int ntype) {
+        return nativeType == ntype;
+    }
+
+    public static VideoFormat formatForType(int ntype) {
+        return lookupMap.get(Integer.valueOf(ntype));
+    }
+
+    // Constants for JNI headers
+    public static class FormatTypes {
+        public static final int FORMAT_TYPE_ARGB = 1;
+        public static final int FORMAT_TYPE_BGRA_PRE = 2;
+        public static final int FORMAT_TYPE_YCBCR_420P = 100;
+        public static final int FORMAT_TYPE_YCBCR_422 = 101;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/control/VideoRenderControl.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.control;
+
+import com.sun.media.jfxmedia.events.VideoFrameRateListener;
+import com.sun.media.jfxmedia.events.VideoRendererListener;
+
+/**
+ * This interface is supported by the player to support video rendering.
+ * It provides methods for registering listeners for getting media frames
+ * and a notification mechanism for when new data is available.
+ */
+public interface VideoRenderControl {
+    /**
+     * Adds the listener to the player's videoUpdate. The listener
+     * will be called whenever a new frame of video is ready to be
+     * painted or fetched by getData()
+     * @param listener the object which provides the VideoUpdateListener
+     * callback interface
+     */
+    public void addVideoRendererListener(VideoRendererListener listener);
+
+    /**
+     * Removes the listener from the player.
+     * @param listener to be removed from the player
+     */
+    public void removeVideoRendererListener(VideoRendererListener listener);
+
+    /**
+     * Adds the listener to the player's <code>VideoRenderControl</code>. The
+     * listener will be invoked when there is a significant change in the
+     * decoded video frame rate.
+     *
+     * @param listener
+     */
+    public void addVideoFrameRateListener(VideoFrameRateListener listener);
+
+    /**
+     * Remove the listener from the player's <code>VideoRenderControl</code>.
+     *
+     * @param listener
+     */
+    public void removeVideoFrameRateListener(VideoFrameRateListener listener);
+
+    /**
+     * Gets the width of a video frame
+     *
+     * @return An integer value for the width.
+     */
+    public int getFrameWidth();
+
+    /**
+     * Gets the height of a video frame
+     *
+     * @return An integer value for the height.
+     */
+    public int getFrameHeight();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/effects/AudioEqualizer.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.effects;
+
+/**
+ * Provides a master audio equalizer with up to 15 bands.  Each band can have the center frequency,
+ * bandwidth, and gain set.
+ */
+public interface AudioEqualizer
+{
+    /**
+     * The maximum number of bands the equalizer can control.
+     */
+    public static final int MAX_NUM_BANDS = 64;
+
+    /**
+     * Returns whether equalization was enabled or not.
+     *
+     * @return boolean value
+     */
+    public boolean getEnabled();
+
+    /**
+     * Turns on or off audio equalization.
+     *
+     * @param bEnable boolean value
+     */
+    public void setEnabled(boolean bEnable);
+
+    /**
+     * Adds a band to the equalizer.
+     *
+     * @param centerFrequency
+     * @param bandwidth
+     * @param gain
+     * @return instance of EqualizerBand if the band was added, null if a band with the
+     * <code>centerFrequency</code> already exists.
+     * @throws IllegalArgumentException if <code>centerFrequency</code> or <code>bandwidth</code> are < 0.0.
+     */
+    public EqualizerBand addBand(double centerFrequency, double bandwidth, double gain);
+
+    /**
+     * Removes an equalizer band with the specified center frequency.
+     *
+     * @param centerFrequency
+     * @return true if the band was found and removed.  false otherwise
+     * @throws IllegalArgumentException if <code>centerFrequency</code> is
+     * negative.
+     */
+    public boolean removeBand(double centerFrequency);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/effects/AudioSpectrum.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.effects;
+
+public interface AudioSpectrum {
+    /**
+     * Returns whether audio spectrum is enabled or not.
+     *
+     * @return boolean value
+     */
+    public boolean getEnabled();
+
+    /**
+     * Turns on or off audio spectrum support.
+     *
+     * @param enable boolean value
+     */
+    public void setEnabled(boolean enabled);
+
+    /**
+     * Gets the number of bands in the audio spectrum
+     *
+     * @return int value
+     */
+    public int getBandCount();
+
+    /**
+     * Sets the number of bands in the audio spectrum
+     *
+     * @param bands integer value
+     */
+    public void setBandCount(int bands);
+
+    /**
+     * Returns the interval between <code>AudioSpectrumEvent<code>s in seconds.
+     *
+     * @return double value
+     */
+    public double getInterval();
+
+    /**
+     * Set the interval between <code>AudioSpectrumEvent<code>s in seconds.
+     *
+     * @param interval double value
+     */
+    public void setInterval(double interval);
+
+    /**
+     * Returns sensitivity threshold in dB. All lower values will be set to this.
+     *
+     * @return int value
+     */
+    public int getSensitivityThreshold();
+
+    /**
+     * Sets sensitivity threshold in dB. All lower values will be set to this.
+     * Allowed values: <= 0
+     *
+     * @param threshold int value
+     */
+    public void setSensitivityThreshold(int threshold);
+
+    /**
+     * Returns an array of the last available magnitudes. The size of the array equals
+     * the number of bands set by the {@link #setBandCount(int) setBandCount(int)} method.
+     * A newly created array contains {@link Float#NEGATIVE_INFINITY Float.NEGATIVE_INFINITY}
+     * values. When the number of bands is 0 this method returns an empty array.
+     * If a non-null array large enough to hold the values is passed in, it will
+     * be used; otherwise a newly allocated array will be returned.
+     *
+     * @param magnitudes An optionally preallocated double array.
+     * @return array of float values.
+     */
+    public float[] getMagnitudes(float[] magnitudes);
+
+    /**
+     * Returns an array of the last available phases. The size of the array equals
+     * the number of bands set by the {@link #setBandCount(int) setBandCount(int)}
+     * method. A newly created array contains 0.0 values. When the number of bands
+     * is 0 this method returns an empty array. If a non-null array large enough
+     * to hold the values is passed in, it will be used; otherwise a newly
+     * allocated array will be returned.
+     *
+     * @param phases An optionally preallocated double array.
+     * @return array of float values.
+     */
+    public float[] getPhases(float[] phases);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/effects/EqualizerBand.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.effects;
+
+/**
+ * EqualizerBand represents a single band in AudioEqualizer.  EqualizerBand can specify the center
+ * frequency, bandwidth, and gain on the band.
+ *
+ * @see AudioEqualizer
+ */
+public interface EqualizerBand
+{
+    /**
+     * Minimum possible gain.
+     */
+    public static final double MIN_GAIN = -24.0;
+
+    /**
+     * Maximum possible gain.
+     */
+    public static final double MAX_GAIN = 12.0;
+
+    /**
+     * Gets the center frequency of this band.  Half of the bandwidth is to the left of this frequncy
+     * and half is to the right.
+     *
+     * @return float value
+     */
+    public double getCenterFrequency();
+
+    /**
+     * Sets the center frequency of this band.  Half of the bandwidth is to the left of this frequncy
+     * and half is to the right.
+     *
+     * @param centerFrequency float value
+     */
+    public void setCenterFrequency(double centerFrequency);
+
+    /**
+     * Gets the bandwith (of frequencies) of this band.
+     *
+     * @return float value
+     */
+    public double getBandwidth();
+
+    /**
+     * Sets the bandwidth of this band.
+     *
+     * @param bandwidth float value
+     */
+    public void setBandwidth(double bandwidth);
+
+    /**
+     * Gets the gain value for this bandwidth.  Gains are in decibels.
+     *
+     * @return float value for dB
+     */
+    public double getGain();
+
+    /**
+     * Sets the gain value for this bandwidth.  Gains are in decibels.
+     *
+     * @param gain float value in dB
+     * @throws IllegalArgumentException if <code>gain</code> is outside of the
+     * platform possible range. For example GStreamer based equalizer gain values
+     * must be in [-24.0; 12.0] interval.
+     */
+    public void setGain(double gain);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/AudioSpectrumEvent.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+import com.sun.media.jfxmedia.effects.AudioSpectrum;
+
+public class AudioSpectrumEvent extends PlayerEvent {
+    private AudioSpectrum source;
+    private double        timestamp;
+    private double        duration;
+
+    public AudioSpectrumEvent(AudioSpectrum source, double timestamp, double duration) {
+        this.source = source;
+        this.timestamp = timestamp;
+        this.duration = duration;
+    }
+
+    public final AudioSpectrum getSource() {
+        return source;
+    }
+
+    public final double getTimestamp() {
+        return timestamp;
+    }
+
+    public final double getDuration() {
+        return duration;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/AudioSpectrumListener.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+public interface AudioSpectrumListener {
+
+    /**
+     * Notification when there is a new AudioSpectrumEvent.
+     *
+     * @param evt AudioSpectrumEvent object.
+     */
+    void onAudioSpectrumEvent(AudioSpectrumEvent evt);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/BufferListener.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+/**
+ * BufferListener is listener for all kinds of buffering events. It receives
+ * notifications from the MediaPlayer.
+ * 1) Any application that needs information about the progress of downloading
+ * remote content to the local cache listens to the BufferProgressEvent.
+ *
+ * @see BufferProgressEvent
+ */
+public interface BufferListener {
+
+    /**
+     * Notification about buffer progress.
+     *
+     * @param evt CacheStateEvent object.
+     */
+    public void onBufferProgress(BufferProgressEvent evt);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/BufferProgressEvent.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+/**
+ * Event class for buffering progress notification.
+ */
+public class BufferProgressEvent extends PlayerEvent {
+
+    private double  duration;
+    private long    start;
+    private long    stop;
+    private long    position;
+
+    /**
+     * Constructor. The state is set to
+     * {@link PlayerStateEvent.PlayerState#STALLED}
+     *
+     * @param start Start position of the buffer
+     * @param size Total size of the buffer in bytes
+     * @param fill Number of bytes loaded
+     */
+    public BufferProgressEvent(double duration, long start, long stop, long position) {
+        this.duration = duration;
+        this.start = start;
+        this.stop = stop;
+        this.position = position;
+    }
+
+    public double getDuration()
+    {
+        return duration;
+    }
+
+    /**
+     * Get buffer start position in bytes.
+     * @return The buffer start position.
+     */
+    public long getBufferStart()
+    {
+        return start;
+    }
+
+    /**
+     * Gets the stop position of the buffer size in bytes.
+     *
+     * @return The buffer stop position.
+     */
+    public long getBufferStop()
+    {
+        return stop;
+    }
+
+    /**
+     * Get the total bytes loaded in the buffer from the 0 position.
+     *
+     * @return The number of bytes loaded.
+     */
+    public long getBufferPosition()
+    {
+        return position;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/MarkerEvent.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+/**
+ * The MarkerEvent is returned on marker notifications to a PlayerStateListener.
+ * Markers may be embedded in the media source or programmatically inserted.
+ *
+ * @see com.sun.media.jfxmedia.Media#addMarker(java.lang.String, double)
+ * @see com.sun.media.jfxmedia.events.PlayerStateListener
+ */
+public class MarkerEvent extends PlayerEvent
+{
+    private String markerName;
+    private double presentationTime;
+
+    /** Constructor.
+     *
+     * @param name The name of the marker.
+     * @param time The presentation (stream) time of the marker.
+     * @throws IllegalArgumentException if <code>name</code> is <code>null</code>
+     * or <code>time&lt;0.0</code>.
+     */
+    public MarkerEvent(String name, double time) {
+        if (name == null) {
+            throw new IllegalArgumentException("name == null!");
+        } else if (time < 0.0) {
+            throw new IllegalArgumentException("time < 0.0!");
+        }
+
+        this.markerName = name;
+        this.presentationTime = time;
+    }
+
+    /**
+     * Returns the marker name.
+     *
+     * @return The marker name
+     */
+    public String getMarkerName()
+    {
+        return this.markerName;
+    }
+
+    /**
+     * Returns the presentation time of the Marker.
+     *
+     * @return The marker time
+     */
+    public double getPresentationTime()
+    {
+        return this.presentationTime;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/MarkerListener.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+/**
+ * The listener interface for receiving notifications when a marker has been
+ * encountered in the media stream.
+ */
+public interface MarkerListener {
+    /**
+     * The marker notification indicates a marker, embedded or programmatically inserted, has been
+     * reached during playback.
+     *
+     * @param evt
+     */
+    public void onMarker(MarkerEvent evt);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/MediaErrorListener.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+/**
+ * An interface used to receive notifications of errors, encountered while
+ * processing media.
+ */
+public interface MediaErrorListener {
+    /**
+     * Reports the occurrence of a error in media processing.  An error may
+     * or may not cause a stop in processing.
+     *
+     * @param source the source of the warning, likely the object calling this
+     * method.
+     * @param errorCode an error code from the internal playback processor
+     * @param message a <code>String</code> containing the warning.
+     */
+    void onError(Object source, int errorCode, String message);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/MetadataListener.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+import java.util.Map;
+
+/**
+ * The listener interface for receiving notifications when a metadata has been
+ * encountered in the media stream.
+ */
+public interface MetadataListener {
+
+    /**
+     * The metadata notification indicates a metadata has been
+     * reached or metadata value was changed during playback.
+     *
+     * @param metadata
+     */
+    public void onMetadata(Map<String, Object> metadata);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/NewFrameEvent.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+import com.sun.media.jfxmedia.control.VideoDataBuffer;
+
+/**
+ * Event indicating that a new video frame has been decoded.
+ */
+public class NewFrameEvent extends PlayerEvent {
+
+    private VideoDataBuffer frameData;
+
+    /**
+     * The constructor for the <code>VideoDataBuffer</code>.
+     *
+     * @param buffer The video frame.
+     * @throws IllegalArgumentException if <code>buffer</code> is
+     * <code>null</code>.
+     */
+    public NewFrameEvent(VideoDataBuffer buffer) {
+        if (buffer == null) {
+            throw new IllegalArgumentException("buffer == null!");
+        }
+        frameData = buffer;
+    }
+
+    /**
+     * The video buffer.
+     *
+     * @return The event's data.
+     */
+    public VideoDataBuffer getFrameData() {
+        return frameData;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/PlayerEvent.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+/**
+ * Marker class for all events emitted by a media player.
+ */
+public class PlayerEvent {
+    public PlayerEvent() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/PlayerStateEvent.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+import com.sun.media.jfxmediaimpl.MediaUtils;
+
+/**
+ * An event indicating a change in the state of a media player.
+ */
+public class PlayerStateEvent extends PlayerEvent {
+
+    public enum PlayerState {
+
+        UNKNOWN, READY, PLAYING, PAUSED, STOPPED, STALLED, FINISHED, HALTED
+    };
+
+    private PlayerState playerState;
+    private double playerTime;
+    private String message;
+
+    /**
+     * Constructor.
+     *
+     * @param state The state of the player.
+     * @param time The time in seconds when this event occurred.
+     * @throws IllegalArgumentException if <code>state</code> is <code>null</code>
+     * or <code>time&lt;0.0</code>.
+     */
+    public PlayerStateEvent(PlayerState state, double time) {
+        if (state == null) {
+            throw new IllegalArgumentException("state == null!");
+        } else if (time < 0.0) {
+            throw new IllegalArgumentException("time < 0.0!");
+        }
+
+        this.playerState = state;
+        this.playerTime = time;
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param state The state of the player.
+     * @param time The time in seconds when this event occurred.
+     * @param message Carries auxiliary message. HALTED state has additional information.
+     * @throws IllegalArgumentException if <code>state</code> is <code>null</code>
+     * or <code>time&lt;0.0</code>.
+     */
+    public PlayerStateEvent(PlayerState state, double time, String message) {
+        this(state, time);
+        this.message = message;
+    }
+
+    /**
+     * Retrieves the state of the media player.
+     *
+     * @return The player's state.
+     */
+    public PlayerState getState() {
+        return playerState;
+    }
+
+    /**
+     * Presentation time when the event occurred.
+     *
+     * @return The time in seconds of the state transition.
+     */
+    public double getTime() {
+        return playerTime;
+    }
+
+    /**
+     * Auxiliary message information when available.
+     *
+     * @return The message or null.
+     */
+    public String getMessage() {
+        return message;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/PlayerStateListener.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+/**
+ * Notifications related to playing media are sent to PlayerStateListener.
+ */
+public interface PlayerStateListener
+{
+    /**
+     * The ready state indicates the media is loaded.
+     * For best results, developers should wait on OnReady() before playing a media.
+     *
+     * @param evt
+     */
+    public void onReady(PlayerStateEvent evt);
+
+    /**
+     * The play state indicates the media is beginning to play.
+     *
+     * @param evt
+     */
+    public void onPlaying(PlayerStateEvent evt);
+
+    /**
+     * The pause state indicates playback has paused.
+     *
+     * @param evt
+     */
+    public void onPause(PlayerStateEvent evt);
+
+    /**
+     * The stop state indicates playback has paused and presentation time has been reset back to 0.
+     * If the player is asked to play() again, playback begins from the beginning.
+     *
+     * @param evt
+     */
+    public void onStop(PlayerStateEvent evt);
+
+    public void onStall(PlayerStateEvent evt);
+
+
+    /**
+     * The finish state indicates playback has completed playback to the end.
+     *
+     * @param evt
+     */
+    public void onFinish(PlayerStateEvent evt);
+
+    /**
+     * The error notification provides information on any error during playback.
+     *
+     * @param evt
+     */
+    public void onHalt(PlayerStateEvent evt);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/PlayerTimeListener.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+/**
+ * Notifications of updates to time-related playback parameters are sent here.
+ */
+public interface PlayerTimeListener {
+
+    /**
+     * Invoked when there is an update to the duration estimate.
+     *
+     * @param duration the duration in seconds.
+     */
+    public void onDurationChanged(double duration);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/VideoFrameRateListener.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+/**
+ * A listener interface for monitoring the video frame rate.
+ */
+public interface VideoFrameRateListener {
+    /**
+     * The video frame rate in frames per second.
+     *
+     * @param videoFrameRate The video frame rate in frames per second.
+     */
+    public void onFrameRateChanged(double videoFrameRate);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/VideoRendererListener.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+/**
+ * The listener interface for receiving video renderer events.
+ */
+public interface VideoRendererListener {
+    /**
+     * Notifies the listener that a new frame is available for rendering.
+     *
+     * @param event The event.
+     */
+    public void videoFrameUpdated(NewFrameEvent event);
+
+    /**
+     * Notifies the listener that it needs to release video frames.
+     *
+     */
+    public void releaseVideoFrames();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/events/VideoTrackSizeListener.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.events;
+
+/**
+ * The listener interface for receiving notifications that the video frame
+ * dimensions have changed.
+ */
+public interface VideoTrackSizeListener {
+
+    /**
+     * The size notification indicates the dimension of the video has changed.
+     *
+     * @param width The new width of the video frames.
+     * @param height The new height of the video frames.
+     */
+    public void onSizeChanged(int width, int height);
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/locator/ConnectionHolder.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,452 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.locator;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.net.HttpURLConnection;
+import java.net.JarURLConnection;
+import java.net.URI;
+import java.net.URLConnection;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.ClosedChannelException;
+import java.nio.channels.FileChannel;
+import java.nio.channels.ReadableByteChannel;
+import java.util.Map;
+
+/**
+ * Connection holders hold and maintain connection do different kinds of sources
+ *
+ */
+public abstract class ConnectionHolder {
+    private static int DEFAULT_BUFFER_SIZE = 4096;
+
+    ReadableByteChannel channel;
+    ByteBuffer          buffer = ByteBuffer.allocateDirect(DEFAULT_BUFFER_SIZE);
+
+    static ConnectionHolder createMemoryConnectionHolder(ByteBuffer buffer) {
+        return new MemoryConnectionHolder(buffer);
+    }
+
+    static ConnectionHolder createURIConnectionHolder(URI uri, Map<String,Object> connectionProperties) throws IOException {
+        return new URIConnectionHolder(uri, connectionProperties);
+    }
+
+    static ConnectionHolder createFileConnectionHolder(URI uri) throws IOException {
+        return new FileConnectionHolder(uri);
+    }
+
+    static ConnectionHolder createHLSConnectionHolder(URI uri) throws IOException {
+        return new HLSConnectionHolder(uri);
+    }
+
+    /**
+     * Reads a block of data from the current position of the opened stream.
+     *
+     * @return The number of bytes read, possibly zero, or -1 if the channel
+     * has reached end-of-stream.
+     *
+     * @throws ClosedChannelException if an attempt is made to read after
+     * closeConnection has been called
+     */
+    public int readNextBlock() throws IOException {
+        buffer.rewind();
+        if (buffer.limit() < buffer.capacity()) {
+            buffer.limit(buffer.capacity());
+        }
+        // avoid NPE if channel does not exist or has been closed
+        if (null == channel) {
+            throw new ClosedChannelException();
+        }
+        return channel.read(buffer);
+    }
+
+    public ByteBuffer getBuffer() {
+        return buffer;
+    }
+
+    /**
+     * Reads a block of data from the arbitrary position of the opened stream.
+     *
+     * @return The number of bytes read, possibly zero, or -1 if the given position
+     * is greater than or equal to the file's current size.
+     *
+     * @throws ClosedChannelException if an attempt is made to read after
+     * closeConnection has been called
+     */
+    abstract int readBlock(long position, int size) throws IOException;
+
+    /**
+     * Detects whether this source needs buffering at the pipeline level.
+     * When true the pipeline contains progressbuffer after the source.
+     *
+     * @return true if the source needs a buffer, false otherwise.
+     */
+    abstract boolean needBuffer();
+
+    /**
+     * Detects whether the source is seekable.
+     * @return true if the source is seekable, false otherwise.
+     */
+    abstract boolean isSeekable();
+
+    /**
+     * Detects whether the source is a random access source. If the method returns
+     * true then the source is capable of working in pull mode. To be able to work
+     * in pull mode holder must provide implementation.
+     * @return true is the source is random access, false otherwise.
+     */
+    abstract boolean isRandomAccess();
+
+    /**
+     * Performs a seek request to the desired position.
+     *
+     * @return -1 if the seek request failed or new stream position
+     */
+    public abstract long seek(long position);
+
+    /**
+     * Closes connection when done.
+     * Overriding methods should call this method in the beginning of their implementation.
+     */
+    public void closeConnection() {
+        try {
+            if (channel != null) {
+                channel.close();
+            }
+        } catch (IOException ioex) {}
+        finally {
+            channel = null;
+        }
+    }
+
+    /**
+     * Get or set properties.
+     *
+     * @param prop - Property ID.
+     * @param value - Depends on property ID.
+     * @return - Depends on property ID.
+     */
+    int property(int prop, int value) {
+        return 0;
+    }
+
+    /**
+     * Get stream size.
+     * Behavior can vary based on subclass implementation.
+     * For example HLS will load next segment and return segment size.
+     *
+     * @return - Stream size.
+     */
+    int getStreamSize() {
+        return -1;
+    }
+
+    private static class FileConnectionHolder extends ConnectionHolder {
+        private RandomAccessFile file = null;
+
+        FileConnectionHolder(URI uri) throws IOException {
+            channel = openFile(uri);
+        }
+
+        boolean needBuffer() {
+            return false;
+        }
+
+        boolean isRandomAccess() {
+            return true;
+        }
+
+        boolean isSeekable() {
+            return true;
+        }
+
+        public long seek(long position) {
+            try {
+                ((FileChannel)channel).position(position);
+                return position;
+            } catch(IOException ioex) {
+                return -1;
+            }
+        }
+
+        int readBlock(long position, int size) throws IOException {
+            if (null == channel) {
+                throw new ClosedChannelException();
+            }
+
+            if (buffer.capacity() < size) {
+                buffer = ByteBuffer.allocateDirect(size);
+            }
+            buffer.rewind().limit(size);
+            return ((FileChannel)channel).read(buffer, position);
+        }
+
+        private ReadableByteChannel openFile(final URI uri) throws IOException {
+            if (file != null) {
+                file.close();
+            }
+
+            file = new RandomAccessFile(new File(uri), "r");
+            return file.getChannel();
+        }
+
+        @Override
+        public void closeConnection() {
+            super.closeConnection();
+
+            if (file != null) {
+                try {
+                    file.close();
+                } catch (IOException ex) {
+                } finally {
+                    file = null;
+                }
+            }
+        }
+    }
+
+    private static class URIConnectionHolder extends ConnectionHolder {
+        private URI                 uri;
+        private URLConnection       urlConnection;
+
+        URIConnectionHolder(URI uri, Map<String,Object> connectionProperties) throws IOException {
+            this.uri = uri;
+            urlConnection = uri.toURL().openConnection();
+            if (connectionProperties != null) {
+                for(Map.Entry<String,Object> entry : connectionProperties.entrySet()) {
+                    Object value = entry.getValue();
+                    if (value instanceof String) {
+                        urlConnection.setRequestProperty(entry.getKey(), (String)value);
+                    }
+                }
+            }
+            channel = openChannel(null);
+        }
+
+        boolean needBuffer() {
+            String scheme = uri.getScheme().toLowerCase();
+            return "http".equals(scheme);
+        }
+
+        boolean isSeekable() {
+            return (urlConnection instanceof HttpURLConnection) || (urlConnection instanceof JarURLConnection);
+        }
+
+        boolean isRandomAccess() {
+            return false;
+        }
+
+        int readBlock(long position, int size) throws IOException {
+            throw new IOException();
+        }
+
+        public long seek(long position) {
+            if (urlConnection instanceof HttpURLConnection) {
+                URLConnection tmpURLConnection = null;
+                
+                //closeConnection();
+                try{
+                    tmpURLConnection = uri.toURL().openConnection();
+
+                    HttpURLConnection httpConnection = (HttpURLConnection)tmpURLConnection;
+                    httpConnection.setRequestMethod("GET");
+                    httpConnection.setUseCaches(false);
+                    httpConnection.setRequestProperty("Range", "bytes=" + position + "-");
+                    // If range request worked properly we should get responce code 206 (HTTP_PARTIAL)
+                    // Else fail seek and let progressbuffer to download all data. It is pointless for us to download it and throw away.
+                    if (httpConnection.getResponseCode() == HttpURLConnection.HTTP_PARTIAL) {
+                        closeConnection();
+                        urlConnection = tmpURLConnection;
+                        tmpURLConnection = null;
+                        channel = openChannel(null);
+                        return position;
+                    } else {
+                        return -1;
+                    }
+                } catch (IOException ioex) {
+                    return -1;
+                } finally {
+                    if (tmpURLConnection != null) {
+                        Locator.closeConnection(tmpURLConnection);
+                    }
+                }
+            } else if (urlConnection instanceof JarURLConnection) {
+                try {
+                    closeConnection();
+
+                    urlConnection = uri.toURL().openConnection();
+
+                    // Skip data that we do not need
+                    long skip_left = position;
+                    InputStream inputStream = urlConnection.getInputStream();
+                    do {
+                        long skip = inputStream.skip(skip_left);
+                        skip_left -= skip;
+                    } while (skip_left > 0);
+
+                    channel = openChannel(inputStream);
+
+                    return position;
+                } catch (IOException ioex) {
+                    return -1;
+                }
+            }
+
+            return -1;
+        }
+
+        @Override
+        public void closeConnection() {
+            super.closeConnection();
+
+            Locator.closeConnection(urlConnection);
+            urlConnection = null;
+        }
+
+        private ReadableByteChannel openChannel(InputStream inputStream) throws IOException {
+            return (inputStream == null) ?
+                    Channels.newChannel(urlConnection.getInputStream()) :
+                    Channels.newChannel(inputStream);
+        }
+    }
+
+    // A "ConnectionHolder" that "reads" from a ByteBuffer, generally loaded from
+    // some unsupported or buggy source
+    private static class MemoryConnectionHolder extends ConnectionHolder {
+        private final ByteBuffer backingBuffer;
+
+        public MemoryConnectionHolder(ByteBuffer buf) {
+            if (null == buf) {
+                throw new IllegalArgumentException("Can't connect to null buffer...");
+            }
+
+            if (buf.isDirect()) {
+                // we can use it, or rather a duplicate directly
+                backingBuffer = buf.duplicate();
+            } else {
+                // operate on a copy of the buffer
+                backingBuffer = ByteBuffer.allocateDirect(buf.capacity());
+                backingBuffer.put(buf);
+            }
+
+            // rewind since the default position is expected to be at zero
+            backingBuffer.rewind();
+
+            // readNextBlock should never be called since we're random access
+            // but just to be safe (and for unit tests...)
+            channel = new ReadableByteChannel() {
+                public int read(ByteBuffer bb) throws IOException {
+                    if (backingBuffer.remaining() <= 0) {
+                        return -1; // EOS
+                    }
+
+                    int actual;
+                    if (bb.equals(buffer)) {
+                        // we'll cheat here as we know that bb is buffer and rather
+                        // than copy the data, just slice it like for readBlock
+                        actual = Math.min(DEFAULT_BUFFER_SIZE, backingBuffer.remaining());
+                        if (actual > 0) {
+                            buffer = backingBuffer.slice();
+                            buffer.limit(actual);
+                        }
+                    } else {
+                        actual = Math.min(bb.remaining(), backingBuffer.remaining());
+                        if (actual > 0) {
+                            backingBuffer.limit(backingBuffer.position() + actual);
+                            bb.put(backingBuffer);
+                            backingBuffer.limit(backingBuffer.capacity());
+                        }
+                    }
+                    return actual;
+                }
+
+                public boolean isOpen() {
+                    return true; // open 24/7/365
+                }
+
+                public void close() throws IOException {
+                    // never closed...
+                }
+            };
+        }
+
+        @Override
+        int readBlock(long position, int size) throws IOException {
+            // mimic stream behavior
+            if (null == channel) {
+                throw new ClosedChannelException();
+            }
+
+            if ((int)position > backingBuffer.capacity()) {
+                return -1; //EOS
+            }
+            backingBuffer.position((int)position);
+
+            buffer = backingBuffer.slice();
+
+            int actual = Math.min(backingBuffer.remaining(), size);
+            buffer.limit(actual); // only give as much as asked
+            backingBuffer.position(backingBuffer.position() + actual);
+
+            return actual;
+        }
+
+        @Override
+        boolean needBuffer() {
+            return false;
+        }
+
+        @Override
+        boolean isSeekable() {
+            return true;
+        }
+
+        @Override
+        boolean isRandomAccess() {
+            return true;
+        }
+
+        @Override
+        public long seek(long position) {
+            if ((int)position < backingBuffer.capacity()) {
+                backingBuffer.limit(backingBuffer.capacity());
+                backingBuffer.position((int)position);
+                return position;
+            }
+            return -1;
+        }
+
+        @Override
+        public void closeConnection() {
+            // more stream behavior mimicry
+            channel = null;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/locator/HLSConnectionHolder.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,908 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.locator;
+
+import com.sun.media.jfxmedia.MediaError;
+import com.sun.media.jfxmediaimpl.MediaUtils;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.*;
+import java.nio.channels.Channels;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.Semaphore;
+
+final class HLSConnectionHolder extends ConnectionHolder {
+
+    private URLConnection urlConnection = null;
+    private PlaylistThread playlistThread = new PlaylistThread();
+    private VariantPlaylist variantPlaylist = null;
+    private Playlist currentPlaylist = null;
+    private int mediaFileIndex = -1;
+    private CountDownLatch readySignal = new CountDownLatch(1);
+    private Semaphore liveSemaphore = new Semaphore(0);
+    private boolean isPlaylistClosed = false;
+    private boolean isBitrateAdjustable = false;
+    private long startTime = -1;
+    private static final long HLS_VALUE_FLOAT_MULTIPLIER = 1000;
+    private static final int HLS_PROP_GET_DURATION = 1;
+    private static final int HLS_PROP_GET_HLS_MODE = 2;
+    private static final int HLS_PROP_GET_MIMETYPE = 3;
+    private static final int HLS_VALUE_MIMETYPE_MP2T = 1;
+    private static final int HLS_VALUE_MIMETYPE_MP3 = 2;
+    private static final String CHARSET_UTF_8 = "UTF-8";
+    private static final String CHARSET_US_ASCII = "US-ASCII";
+
+    HLSConnectionHolder(URI uri) throws IOException {
+        playlistThread.setPlaylistURI(uri);
+        init();
+    }
+
+    private void init() {
+        playlistThread.putState(PlaylistThread.STATE_INIT);
+        playlistThread.start();
+    }
+
+    @Override
+    public int readNextBlock() throws IOException {
+        if (isBitrateAdjustable && startTime == -1) {
+            startTime = System.currentTimeMillis();
+        }
+
+        int read = super.readNextBlock();
+        if (isBitrateAdjustable && read == -1) {
+            long readTime = System.currentTimeMillis() - startTime;
+            startTime = -1;
+            adjustBitrate(readTime);
+        }
+
+        return read;
+    }
+
+    int readBlock(long position, int size) throws IOException {
+        throw new IOException();
+    }
+
+    boolean needBuffer() {
+        return true;
+    }
+
+    boolean isSeekable() {
+        return true;
+    }
+
+    boolean isRandomAccess() {
+        return false; // Only by segments
+    }
+
+    public long seek(long position) {
+        try {
+            readySignal.await();
+        } catch (Exception e) {
+            return -1;
+        }
+
+        return (long) (currentPlaylist.seek(position) * HLS_VALUE_FLOAT_MULTIPLIER);
+    }
+
+    @Override
+    public void closeConnection() {
+        currentPlaylist.close();
+        super.closeConnection();
+        resetConnection();
+        playlistThread.putState(PlaylistThread.STATE_EXIT);
+    }
+
+    @Override
+    int property(int prop, int value) {
+        try {
+            readySignal.await();
+        } catch (Exception e) {
+            return -1;
+        }
+
+        if (prop == HLS_PROP_GET_DURATION) {
+            return (int) (currentPlaylist.getDuration() * HLS_VALUE_FLOAT_MULTIPLIER);
+        } else if (prop == HLS_PROP_GET_HLS_MODE) {
+            return 1;
+        } else if (prop == HLS_PROP_GET_MIMETYPE) {
+            return currentPlaylist.getMimeType();
+        }
+
+        return -1;
+    }
+
+    @Override
+    int getStreamSize() {
+        try {
+            readySignal.await();
+        } catch (Exception e) {
+            return -1;
+        }
+
+        return loadNextSegment();
+    }
+
+    private void resetConnection() {
+        super.closeConnection();
+
+        Locator.closeConnection(urlConnection);
+        urlConnection = null;
+    }
+
+    // Returns -1 EOS or critical error
+    // Returns positive size of segment if no isssues.
+    // Returns negative size of segment if discontinuity.
+    private int loadNextSegment() {
+        resetConnection();
+
+        String mediaFile = currentPlaylist.getNextMediaFile();
+        if (mediaFile == null) {
+            return -1;
+        }
+
+        try {
+            URI uri = new URI(mediaFile);
+            urlConnection = uri.toURL().openConnection();
+            channel = openChannel();
+        } catch (Exception e) {
+            return -1;
+        }
+
+        if (currentPlaylist.isCurrentMediaFileDiscontinuity()) {
+            return (-1 * urlConnection.getContentLength());
+        } else {
+            return urlConnection.getContentLength();
+        }
+    }
+
+    private ReadableByteChannel openChannel() throws IOException {
+        return Channels.newChannel(urlConnection.getInputStream());
+    }
+
+    private void adjustBitrate(long readTime) {
+        int avgBitrate = (int)(((long) urlConnection.getContentLength() * 8 * 1000) / readTime);
+
+        Playlist playlist = variantPlaylist.getPlaylistBasedOnBitrate(avgBitrate);
+        if (playlist != null && playlist != currentPlaylist) {
+            if (currentPlaylist.isLive()) {
+                playlist.update(currentPlaylist.getNextMediaFile());
+                playlistThread.setReloadPlaylist(playlist);
+            }
+
+            playlist.setForceDiscontinuity(true);
+            currentPlaylist = playlist;
+        }
+    }
+
+    private static String stripParameters(String mediaFile) {
+        int qp = mediaFile.indexOf('?');
+        if (qp > 0) {
+            mediaFile = mediaFile.substring(0, qp); // Strip all possible http parameters.
+        }
+        return mediaFile;
+    }
+
+    private class PlaylistThread extends Thread {
+
+        public static final int STATE_INIT = 0;
+        public static final int STATE_EXIT = 1;
+        public static final int STATE_RELOAD_PLAYLIST = 2;
+        private BlockingQueue<Integer> stateQueue = new LinkedBlockingQueue<Integer>();
+        private URI playlistURI = null;
+        private Playlist reloadPlaylist = null;
+        private final Object reloadLock = new Object();
+        private volatile boolean stopped = false;
+
+        private PlaylistThread() {
+            setName("JFXMedia HLS Playlist Thread");
+            setDaemon(true);
+        }
+
+        private void setPlaylistURI(URI playlistURI) {
+            this.playlistURI = playlistURI;
+        }
+
+        private void setReloadPlaylist(Playlist playlist) {
+            synchronized(reloadLock) {
+                reloadPlaylist = playlist;
+            }
+        }
+
+        @Override
+        public void run() {
+            while (!stopped) {
+                try {
+                    int state = stateQueue.take();
+                    switch (state) {
+                        case STATE_INIT:
+                            stateInit();
+                            break;
+                        case STATE_EXIT:
+                            stopped = true;
+                            break;
+                        case STATE_RELOAD_PLAYLIST:
+                            stateReloadPlaylist();
+                            break;
+                        default:
+                            break;
+                    }
+                } catch (Exception e) {
+                }
+            }
+        }
+
+        private void putState(int state) {
+            if (stateQueue != null) {
+                try {
+                    stateQueue.put(state);
+                } catch (InterruptedException ex) {
+                }
+            }
+        }
+
+        private void stateInit() {
+            if (playlistURI == null) {
+                return;
+            }
+
+            PlaylistParser parser = new PlaylistParser();
+            parser.load(playlistURI);
+
+            if (parser.isVariantPlaylist()) {
+                variantPlaylist = new VariantPlaylist(playlistURI);
+
+                while (parser.hasNext()) {
+                    variantPlaylist.addPlaylistInfo(parser.getString(), parser.getInteger());
+                }
+            } else {
+                if (currentPlaylist == null) {
+                    currentPlaylist = new Playlist(parser.isLivePlaylist(), parser.getTargetDuration());
+                    currentPlaylist.setPlaylistURI(playlistURI);
+                }
+
+                if (currentPlaylist.setSequenceNumber(parser.getSequenceNumber())) {
+                    while (parser.hasNext()) {
+                        currentPlaylist.addMediaFile(parser.getString(), parser.getDouble(), parser.getBoolean());
+                    }
+                }
+
+                if (variantPlaylist != null) {
+                    variantPlaylist.addPlaylist(currentPlaylist);
+                }
+            }
+
+            // Update variant playlists
+            if (variantPlaylist != null) {
+                while (variantPlaylist.hasNext()) {
+                    try {
+                        currentPlaylist = new Playlist(variantPlaylist.getPlaylistURI());
+                        currentPlaylist.update(null);
+                        variantPlaylist.addPlaylist(currentPlaylist);
+                    } catch (URISyntaxException e) {
+                    } catch (MalformedURLException e) {
+                    }
+                }
+            }
+
+            // Always start with first data playlist
+            if (variantPlaylist != null) {
+                currentPlaylist = variantPlaylist.getPlaylist(0);
+                isBitrateAdjustable = true;
+            }
+
+            // Start reloading live playlist
+            if (currentPlaylist.isLive()) {
+                setReloadPlaylist(currentPlaylist);
+                putState(STATE_RELOAD_PLAYLIST);
+            }
+
+            readySignal.countDown();
+        }
+
+        private void stateReloadPlaylist() {
+            try {
+                long timeout;
+                synchronized(reloadLock) {
+                    timeout = reloadPlaylist.getTargetDuration() / 2;
+                }
+                Thread.sleep(timeout);
+            } catch (InterruptedException ex) {
+                return;
+            }
+
+            synchronized(reloadLock) {
+                reloadPlaylist.update(null);
+            }
+
+            putState(STATE_RELOAD_PLAYLIST);
+        }
+    }
+
+    private static class PlaylistParser {
+
+        private boolean isFirstLine = true;
+        private boolean isLineMediaFileURI = false;
+        private boolean isEndList = false;
+        private boolean isLinePlaylistURI = false;
+        private boolean isVariantPlaylist = false;
+        private boolean isDiscontinuity = false;
+        private int targetDuration = 0;
+        private int sequenceNumber = 0;
+        private int dataListIndex = -1;
+        private List<String> dataListString = new ArrayList<String>();
+        private List<Integer> dataListInteger = new ArrayList<Integer>();
+        private List<Double> dataListDouble = new ArrayList<Double>();
+        private List<Boolean> dataListBoolean = new ArrayList<Boolean>();
+
+        private void load(URI uri) {
+            HttpURLConnection connection = null;
+            BufferedReader reader = null;
+            try {
+                connection = (HttpURLConnection) uri.toURL().openConnection();
+                connection.setRequestMethod("GET");
+
+                if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
+                    MediaUtils.error(this, MediaError.ERROR_LOCATOR_CONNECTION_LOST.code(), "HTTP responce code: " + connection.getResponseCode(), null);
+                }
+
+                Charset charset = getCharset(uri.toURL().toExternalForm(), connection.getContentType());
+                if (charset != null) {
+                    reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), charset));
+                }
+
+                if (reader != null) {
+                    boolean result;
+                    do {
+                        result = parseLine(reader.readLine());
+                    } while (result);
+                }
+            } catch (MalformedURLException e) {
+            } catch (IOException e) {
+            } finally {
+                if (reader != null) {
+                    try {
+                        reader.close();
+                    } catch (IOException e) {}
+
+                    Locator.closeConnection(connection);
+                }
+            }
+        }
+
+        private boolean isVariantPlaylist() {
+            return isVariantPlaylist;
+        }
+
+        private boolean isLivePlaylist() {
+            return !isEndList;
+        }
+
+        private int getTargetDuration() {
+            return targetDuration;
+        }
+
+        private int getSequenceNumber() {
+            return sequenceNumber;
+        }
+
+        private boolean hasNext() {
+            dataListIndex++;
+            if (dataListString.size() > dataListIndex || dataListInteger.size() > dataListIndex || dataListDouble.size() > dataListIndex || dataListBoolean.size() > dataListIndex) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        private String getString() {
+            return dataListString.get(dataListIndex);
+        }
+
+        private Integer getInteger() {
+            return dataListInteger.get(dataListIndex);
+        }
+
+        private Double getDouble() {
+            return dataListDouble.get(dataListIndex);
+        }
+
+        private Boolean getBoolean() {
+            return dataListBoolean.get(dataListIndex);
+        }
+
+        private boolean parseLine(String line) {
+            if (line == null) {
+                return false;
+            }
+
+            // First line of playlist must be "#EXTM3U"
+            if (isFirstLine) {
+                if (line.compareTo("#EXTM3U") != 0) {
+                    return false;
+                }
+
+                isFirstLine = false;
+                return true;
+            }
+
+            // Ignore blank lines and comments
+            if (line.isEmpty() || (line.startsWith("#") && !line.startsWith("#EXT"))) {
+                return true;
+            }
+
+            if (line.startsWith("#EXTINF")) { // #EXTINF
+                //#EXTINF:<duration>,<title>
+                String[] s1 = line.split(":");
+                if (s1.length == 2 && s1[1].length() > 0) {
+                    String[] s2 = s1[1].split(",");
+                    if (s2.length >= 1) { // We have duration
+                        dataListDouble.add(Double.parseDouble(s2[0]));
+                    }
+                }
+
+                isLineMediaFileURI = true;
+            } else if (line.startsWith("#EXT-X-TARGETDURATION")) {
+                // #EXT-X-TARGETDURATION:<s>
+                String[] s1 = line.split(":");
+                if (s1.length == 2 && s1[1].length() > 0) {
+                    targetDuration = Integer.parseInt(s1[1]);
+                }
+            } else if (line.startsWith("#EXT-X-MEDIA-SEQUENCE")) {
+                // #EXT-X-MEDIA-SEQUENCE:<number>
+                String[] s1 = line.split(":");
+                if (s1.length == 2 && s1[1].length() > 0) {
+                    sequenceNumber = Integer.parseInt(s1[1]);
+                }
+            } else if (line.startsWith("#EXT-X-STREAM-INF")) {
+                // #EXT-X-STREAM-INF:<attribute-list>
+                isVariantPlaylist = true;
+
+                int bitrate = 0;
+                String[] s1 = line.split(":");
+                if (s1.length == 2 && s1[1].length() > 0) {
+                    String[] s2 = s1[1].split(",");
+                    if (s2.length > 0) {
+                        for (int i = 0; i < s2.length; i++) {
+                            s2[i] = s2[i].trim();
+                            if (s2[i].startsWith("BANDWIDTH")) {
+                                String[] s3 = s2[i].split("=");
+                                if (s3.length == 2 && s3[1].length() > 0) {
+                                    bitrate = Integer.parseInt(s3[1]);
+                                }
+                            }
+                        }
+                    }
+                }
+
+                if (bitrate < 1) {
+                    return false;
+                }
+
+                dataListInteger.add(bitrate);
+
+                isLinePlaylistURI = true; // Next line will be URI to playlist
+            } else if (line.startsWith("#EXT-X-ENDLIST")) { // #EXT-X-ENDLIST
+                isEndList = true;
+            } else if (line.startsWith("#EXT-X-DISCONTINUITY")) { // #EXT-X-DISCONTINUITY
+                isDiscontinuity = true;
+            } else if (isLinePlaylistURI) {
+                isLinePlaylistURI = false;
+                dataListString.add(line);
+            } else if (isLineMediaFileURI) {
+                isLineMediaFileURI = false;
+                dataListString.add(line);
+                dataListBoolean.add(isDiscontinuity);
+                isDiscontinuity = false;
+            }
+
+            return true;
+        }
+
+        private Charset getCharset(String url, String mimeType) {
+            if ((url != null && stripParameters(url).endsWith(".m3u8")) || (mimeType != null && mimeType.equals("application/vnd.apple.mpegurl"))) {
+                if (Charset.isSupported(CHARSET_UTF_8)) {
+                    return Charset.forName(CHARSET_UTF_8);
+                }
+            } else if ((url != null && stripParameters(url).endsWith(".m3u")) || (mimeType != null && mimeType.equals("audio/mpegurl"))) {
+                if (Charset.isSupported(CHARSET_US_ASCII)) {
+                    return Charset.forName(CHARSET_US_ASCII);
+                }
+            }
+
+            return null;
+        }
+    }
+
+    private static class VariantPlaylist {
+
+        private URI playlistURI = null;
+        private int infoIndex = -1;
+        private List<String> playlistsLocations = new ArrayList<String>();
+        private List<Integer> playlistsBitrates = new ArrayList<Integer>();
+        private List<Playlist> playlists = new ArrayList<Playlist>();
+        private String mediaFileExtension = null; // Will be set to media file extension of first playlist
+
+        private VariantPlaylist(URI uri) {
+            playlistURI = uri;
+        }
+
+        private void addPlaylistInfo(String location, int bitrate) {
+            playlistsLocations.add(location);
+            playlistsBitrates.add(bitrate);
+        }
+
+        private void addPlaylist(Playlist playlist) {
+            if (mediaFileExtension == null) {
+                mediaFileExtension = playlist.getMediaFileExtension();
+            } else {
+                if (!mediaFileExtension.equals(playlist.getMediaFileExtension())) {
+                    playlistsLocations.remove(infoIndex);
+                    playlistsBitrates.remove(infoIndex);
+                    infoIndex--;
+                    return; // Ignore playlist with different media type
+                }
+            }
+            playlists.add(playlist);
+        }
+
+        private Playlist getPlaylist(int index) {
+            if (playlists.size() > index) {
+                return playlists.get(index);
+            } else {
+                return null;
+            }
+        }
+
+        private boolean hasNext() {
+            infoIndex++;
+            if (playlistsLocations.size() > infoIndex && playlistsBitrates.size() > infoIndex) {
+                return true;
+            } else {
+                return false;
+            }
+        }
+
+        private URI getPlaylistURI() throws URISyntaxException, MalformedURLException {
+            String location = playlistsLocations.get(infoIndex);
+            if (location.startsWith("http://")) {
+                return new URI(location);
+            } else {
+                return new URI(playlistURI.toURL().toString().substring(0, playlistURI.toURL().toString().lastIndexOf("/") + 1) + location);
+            }
+        }
+
+        private Playlist getPlaylistBasedOnBitrate(int bitrate) {
+            int playlistIndex = -1;
+            int playlistBitrate = 0;
+
+            // Get bitrate that less then requested bitrate, but most closed to it
+            for (int i = 0; i < playlistsBitrates.size(); i++) {
+                int b = playlistsBitrates.get(i);
+                if (b < bitrate) {
+                    if (playlistIndex != -1) {
+                        if (b > playlistBitrate) {
+                            playlistBitrate = b;
+                            playlistIndex = i;
+                        }
+                    } else {
+                        playlistIndex = i;
+                    }
+                }
+            }
+
+            // If we did not find one (stall), then get the lowest bitrate possible
+            if (playlistIndex == -1) {
+                for (int i = 0; i < playlistsBitrates.size(); i++) {
+                    int b = playlistsBitrates.get(i);
+                    if (b < playlistBitrate || playlistIndex == -1) {
+                        playlistBitrate = b;
+                        playlistIndex = i;
+                    }
+                }
+            }
+
+            // Just in case
+            if (playlistIndex < 0 || playlistIndex >= playlists.size()) {
+                return null;
+             } else {
+                return playlists.get(playlistIndex);
+            }
+        }
+    }
+
+    private class Playlist {
+
+        private boolean isLive = false;
+        private volatile boolean isLiveWaiting = false;
+        private volatile boolean isLiveStop = false;
+        private long targetDuration = 0;
+        private URI playlistURI = null;
+        private final Object lock = new Object();
+        private List<String> mediaFiles = new ArrayList<String>();
+        private List<Double> mediaFilesStartTimes = new ArrayList<Double>();
+        private List<Boolean> mediaFilesDiscontinuities = new ArrayList<Boolean>();
+        private boolean needBaseURI = true;
+        private String baseURI = null;
+        private double duration = 0.0;
+        private int sequenceNumber = -1;
+        private int sequenceNumberStart = -1;
+        private boolean sequenceNumberUpdated = false;
+        private boolean forceDiscontinuity = false;
+
+        private Playlist(boolean isLive, int targetDuration) {
+            this.isLive = isLive;
+            this.targetDuration = targetDuration * 1000;
+
+            if (isLive) {
+                duration = -1.0;
+            }
+        }
+
+        private Playlist(URI uri) {
+            playlistURI = uri;
+        }
+
+        private void update(String nextMediaFile) {
+            PlaylistParser parser = new PlaylistParser();
+            parser.load(playlistURI);
+
+            isLive = parser.isLivePlaylist();
+            targetDuration = parser.getTargetDuration() * 1000;
+
+            if (isLive) {
+                duration = -1.0;
+            }
+
+            if (setSequenceNumber(parser.getSequenceNumber())) {
+                while (parser.hasNext()) {
+                    addMediaFile(parser.getString(), parser.getDouble(), parser.getBoolean());
+                }
+            }
+
+            if (nextMediaFile != null) {
+                synchronized (lock) {
+                    for (int i = 0; i < mediaFiles.size(); i++) {
+                        String mediaFile = mediaFiles.get(i);
+                        if (nextMediaFile.endsWith(mediaFile)) {
+                            mediaFileIndex = i - 1;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        private boolean isLive() {
+            return isLive;
+        }
+
+        private long getTargetDuration() {
+            return targetDuration;
+        }
+
+        private void setPlaylistURI(URI uri) {
+            playlistURI = uri;
+        }
+
+        private void addMediaFile(String URI, double duration, boolean isDiscontinuity) {
+            synchronized (lock) {
+
+                if (needBaseURI) {
+                    setBaseURI(playlistURI.toString(), URI);
+                }
+
+                if (isLive) {
+                    if (sequenceNumberUpdated) {
+                        int index = mediaFiles.indexOf(URI);
+                        if (index != -1) {
+                            for (int i = 0; i < index; i++) {
+                                mediaFiles.remove(0);
+                                mediaFilesDiscontinuities.remove(0);
+                                if (mediaFileIndex == -1) {
+                                    forceDiscontinuity = true;
+                                }
+                                if (mediaFileIndex >= 0) {
+                                    mediaFileIndex--;
+                                }
+                            }
+                        }
+                        sequenceNumberUpdated = false;
+                    }
+
+                    if (mediaFiles.contains(URI)) {
+                        return; // Nothing to add
+                    }
+                }
+
+                mediaFiles.add(URI);
+                mediaFilesDiscontinuities.add(isDiscontinuity);
+
+                if (isLive) {
+                    if (isLiveWaiting) {
+                        liveSemaphore.release();
+                    }
+                } else {
+                    mediaFilesStartTimes.add(this.duration);
+                    this.duration += duration;
+                }
+            }
+        }
+
+        private String getNextMediaFile() {            
+            if (isLive) {
+                synchronized (lock) {
+                    isLiveWaiting = ((mediaFileIndex + 1) >= mediaFiles.size());
+                }
+                if (isLiveWaiting) {
+                    try {
+                        liveSemaphore.acquire();
+                        isLiveWaiting = false;
+                        if (isLiveStop) {
+                            isLiveStop = false;
+                            return null;
+                        }
+                    } catch (InterruptedException e) {
+                        isLiveWaiting = false;
+                        return null;
+                    }
+                }
+                if (isPlaylistClosed) {
+                    return null;
+                }
+            }
+
+            synchronized (lock) {
+                mediaFileIndex++;
+                if ((mediaFileIndex) < mediaFiles.size()) {
+                    if (baseURI != null) {
+                        return baseURI + mediaFiles.get(mediaFileIndex);
+                    } else {
+                        return mediaFiles.get(mediaFileIndex);
+                    }
+                } else {
+                    return null;
+                }
+            }
+        }
+
+        private double getDuration() {
+            return duration;
+        }
+
+        private void setForceDiscontinuity(boolean value) {
+            forceDiscontinuity = value;
+        }
+
+        private boolean isCurrentMediaFileDiscontinuity() {
+            if (forceDiscontinuity) {
+                forceDiscontinuity = false;
+                return true;
+            } else {
+                return mediaFilesDiscontinuities.get(mediaFileIndex);
+            }
+        }
+
+        private double seek(long time) {
+            synchronized (lock) {
+                if (isLive) {
+                    if (time == 0) {
+                        mediaFileIndex = -1;
+                        if (isLiveWaiting) {
+                            isLiveStop = true;
+                            liveSemaphore.release();
+                        }
+                        return 0;
+                    }
+                } else {
+                    time += targetDuration / 2000;
+
+                    int mediaFileStartTimeSize = mediaFilesStartTimes.size();
+
+                    for (int index = 0; index < mediaFileStartTimeSize; index++) {
+                        if (time >= mediaFilesStartTimes.get(index)) {
+                            if (index + 1 < mediaFileStartTimeSize) {
+                                if (time < mediaFilesStartTimes.get(index + 1)) {
+                                    mediaFileIndex = index - 1; // Seek will load segment and increment mediaFileIndex
+                                    return mediaFilesStartTimes.get(index);
+                                }
+                            } else {
+                                if ((time - targetDuration / 2000) < duration) {
+                                    mediaFileIndex = index - 1; // Seek will load segment and increment mediaFileIndex
+                                    return mediaFilesStartTimes.get(index);
+                                } else if (Double.compare(time - targetDuration / 2000, duration) == 0) {
+                                    return duration;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            return -1;
+        }
+
+        private int getMimeType() {
+            synchronized (lock) {
+                if (mediaFiles.size() > 0) {
+                    if (stripParameters(mediaFiles.get(0)).endsWith(".ts")) {
+                        return HLS_VALUE_MIMETYPE_MP2T;
+                    } else if (stripParameters(mediaFiles.get(0)).endsWith(".mp3")) {
+                        return HLS_VALUE_MIMETYPE_MP3;
+                    }
+                }
+            }
+
+            return -1;
+        }
+
+        private String getMediaFileExtension() {
+            synchronized (lock) {
+                if (mediaFiles.size() > 0) {
+                    String mediaFile = stripParameters(mediaFiles.get(0));
+                    int index = mediaFile.lastIndexOf(".");
+                    if (index != -1) {
+                        return mediaFile.substring(index);
+                    }
+                }
+            }
+
+            return null;
+        }
+
+        private boolean setSequenceNumber(int value) {
+            if (sequenceNumberStart == -1) {
+                sequenceNumberStart = value;
+            } else if (sequenceNumber != value) {
+                sequenceNumberUpdated = true;
+                sequenceNumber = value;
+            } else {
+                return false;
+            }
+
+            return true;
+        }
+
+        private void close() {
+            if (isLive) {
+                isPlaylistClosed = true;
+                liveSemaphore.release();
+            }
+        }
+
+        private void setBaseURI(String playlistURI, String URI) {
+            if (!URI.startsWith("http://")) {
+                baseURI = playlistURI.substring(0, playlistURI.lastIndexOf("/") + 1);
+            }
+            needBaseURI = false;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/media/src/main/java/com/sun/media/jfxmedia/locator/Locator.java	Mon Oct 21 15:18:12 2013 -0700
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) 2010, 2013, 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.jfxmedia.locator;
+
+import com.sun.media.jfxmedia.MediaException;
+import com.sun.media.jfxmedia.MediaManager;
+import com.sun.media.jfxmedia.logging.Logger;
+import com.sun.media.jfxmediaimpl.HostUtils;
+import com.sun.media.jfxmediaimpl.MediaUtils;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * A
+ * <code>Locator</code> which refers to a
+ * <code>URI</code>.
+ */
+public class Locator {
+
+    /**
+     * The content type used if no more specific one may be derived.
+     */
+    public static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
+    /**
+     * The number of times to attempt to open a URL connection to test the URI.
+     */
+    private static final int MAX_CONNECTION_ATTEMPTS = 5;
+    /**
+     * The number of milliseconds between attempts to open a URL connection.
+     */
+    private static final long CONNECTION_RETRY_INTERVAL = 1000L;
+    /**
+     * The content type of the media content.
+     */
+    protected String contentType = DEFAULT_CONTENT_TYPE;
+    /**
+     * A hint for the internal player.
+     */
+    protected long contentLength = -1;    //Used as a hint for the native layer
+    /**
+     * The URI source.
+     */
+    protected URI uri;
+    /**
+     * Properties to be associated with the connection made to the URI. The
+     * significance of the properties depends on the URI protocol and type of
+     * media source.
+     */
+    private Map<String, Object> connectionProperties;
+    /**
+     * Mutex for connectionProperties;
+     */
+    private final Object propertyLock = new Object();
+
+    /*
+     * These variables will be initialized by constructor and used by init()
+     */
+    private String uriString = null;
+    private String scheme = null;
+    private String protocol = null;
+
+    /*
+     * if cached, we store a hard reference to keep it alive
+     */
+    private LocatorCache.CacheReference cacheEntry = null;
+
+    /*
+     * True if init(), getContentLength() and getContentType() can block; false
+     * otherwise.
+     */
+    private boolean canBlock = false;
+
+    /*
+     * Used to block getContentLength() and getContentType().
+     */
+    private CountDownLatch readySignal = new CountDownLatch(1);
+
+    /**
+     * iOS only: determines if the given URL points to the iPod library
+     */
+    private boolean isIpod;
+
+    /**
+     * Holds connection and response code returned from getConnection()
+     */
+    private static class LocatorConnection {
+
+        public HttpURLConnection connection = null;
+        public int responseCode = HttpURLConnection.HTTP_OK;
+    }
+
+    private LocatorConnection getConnection(URI uri, String requestMethod)
+            throws MalformedURLException, IOException {
+
+        // Check ability to connect.
+        LocatorConnection locatorConnection = new LocatorConnection();
+        HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
+        connection.setRequestMethod(requestMethod);
+
+        // Set request headers.
+        synchronized (propertyLock) {
+            if (connectionProperties != null) {
+                for (String key : connectionProperties.keySet()) {
+                    Object value = connectionProperties.get(key);
+                    if (value instanceof String) {
+                        connection.setRequestProperty(key, (String) value);
+                    }
+                }
+            }
+        }
+
+        // Store response code so we can get more information about
+        // returning connection.
+        locatorConnection.responseCode = connection.getResponseCode();
+        if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
+            locatorConnection.connection = connection;
+        } else {
+            closeConnection(connection);
+            locatorConnection.connection = null;
+        }
+        return locatorConnection;
+    }
+
+    /**
+     * Constructs an object representing a media source.
+     *
+     * @param uri The URI source.
+     * @throws NullPointerException if
+     * <code>uri</code> is
+     * <code>null</code>.
+     * @throws IllegalArgumentException if the URI's scheme is
+     * <code>null</code>.
+     * @throws URISyntaxException if the supplied URI requires some further
+     * manipulation in order to be used and this procedure fails to produce a
+     * usable URI.
+     * @throws IllegalArgumentException if the URI is a Jar URL as described in
+     * {@link JarURLConnection http://download.oracle.com/javase/6/docs/api/java/net/JarURLConnection.html},
+     * and the scheme of the URL after removing the leading four characters is
+     * <code>null</code>.
+     * @throws UnsupportedOperationException if the URI's protocol is
+     * unsupported.
+     */
+    public Locator(URI uri) throws URISyntaxException {
+        // Check for NULL parameter.
+        if (uri == null) {
+            throw new NullPointerException("uri == null!");
+        }
+
+        // Get the scheme part.
+        uriString = uri.toASCIIString();
+        scheme = uri.getScheme();
+        if (scheme == null) {
+            throw new IllegalArgumentException("uri.getScheme() == null! uri == '" + uri + "'");
+        }
+        scheme = scheme.toLowerCase();
+
+        // Get the protocol.
+        if (scheme.equals("jar")) {
+            URI subURI = new URI(uriString.substring(4));
+            protocol = subURI.getScheme();
+            if (protocol == null) {
+                throw new IllegalArgumentException("uri.getScheme() == null! subURI == '" + subURI + "'");
+            }
+            protocol = protocol.toLowerCase();
+        } else {
+            protocol = scheme; // scheme is already lower case.
+        }
+
+        if (HostUtils.isIOS() && protocol.equals("ipod-library")) {
+            isIpod = true;
+        }
+
+        // Verify the protocol is supported.
+        if (!isIpod && !protocol.equals("file") && !protocol.equals("http")) {
+            throw new UnsupportedOperationException("Unsupported protocol \"" + protocol + "\"");
+        }
+
+        // Check if we can block
+        if (protocol.equals("http")) {
+            canBlock = true;
+        }
+
+        // Set instance variable.
+        this.uri = uri;
+    }
+
+    private InputStream getInputStream(URI uri)
+            throws MalformedURLException, IOException {
+        URL url = uri.toURL();
+        URLConnection connection = url.openConnection();
+
+        // Set request headers.
+        synchronized (propertyLock) {
+            if (connectionProperties != null) {
+                for (String key : connectionProperties.keySet()) {
+                    Object value = connectionProperties.get(key);
+                    if (value instanceof String) {
+                        connection.setRequestProperty(key, (String) value);
+                    }
+                }
+            }
+        }
+
+        InputStream inputStream = url.openStream();
+        contentLength = connection.getContentLengthLong();
+        return inputStream;
+    }
+
+    /**
+     * Tell this Locator to preload the media into memory, if it hasn't been
+     * already.
+     */
+    public void cacheMedia() {
+        LocatorCache.CacheReference ref = LocatorCache.locatorCache().fetchURICache(uri);
+        if (null == ref) {
+            ByteBuffer cacheBuffer;
+
+            // not cached, load it
+            InputStream is;
+            try {
+                is = getInputStream(uri);
+            } catch (Throwable t) {
+                return; // just bail
+            }
+
+            // contentLength is set now, so we can go ahead and allocate
+            cacheBuffer = ByteBuffer.allocateDirect((int) contentLength);
+            byte[] readBuf = new byte[8192];
+            int total = 0;
+            int count;
+            while (total < contentLength) {
+                try {
+                    count = is.read(readBuf);
+                } catch (IOException ioe) {
+                    try {
+                        is.close();
+                    } catch (Throwable t) {
+                    }
+                    if (Logger.canLog(Logger.DEBUG)) {
+                        Logger.logMsg(Logger.DEBUG, "IOException trying to preload media: " + ioe);
+                    }
+                    return;
+                }
+
+                if (count == -1) {
+                    break; // EOS
+                }
+
+                cacheBuffer.put(readBuf, 0, count);
+            }
+
+            try {
+                is.close();
+            } catch (Throwable t) {
+            }
+
+            cacheEntry = LocatorCache.locatorCache().registerURICache(uri, cacheBuffer, contentType);
+            canBlock = false;
+        }
+    }
+
+    /*
+     * True if init() can block; false otherwise.
+     */
+    public boolean canBlock() {
+        return canBlock;
+    }
+
+    /*
+     * Initialize locator. Use canBlock() to determine if init() can block.
+     *
+     * @throws URISyntaxException if the supplied URI requires some further
+     * manipulation in order to be used and this procedure fails to produce a
+     * usable URI. @throws IOExceptions if a stream cannot be opened over a
+     * connection of the corresponding URL. @throws MediaException if the
+     * content type of the media is not supported. @throws FileNotFoundException
+     * if the media is not available.
+     */
+    public void init() throws URISyntaxException, IOException, FileNotFoundException {
+        try {
+            // Ensure the correct number of '/'s follows the ':'.
+            int firstSlash = uriString.indexOf("/");
+            if (firstSlash != -1 && uriString.charAt(firstSlash + 1) != '/') {
+                // Only one '/' after the ':'.
+                if (protocol.equals("file")) {
+                    // Map file:/somepath to file:///somepath
+                    uriString = uriString.replaceFirst("/", "///");
+                } else if (protocol.equals("http")) {
+                    // Map http:/somepath to http://somepath
+                    uriString = uriString.replaceFirst("/", "//");
+                }
+            }
+
+            // On non-Windows systems, replace "/~/" with home directory path + "/".
+            if (System.getProperty("os.name").toLowerCase().indexOf("win") == -1
+                    && protocol.equals("file")) {
+                int index = uriString.indexOf("/~/");
+                if (index != -1) {
+                    uriString = uriString.substring(0, index)
+                            + System.getProperty("user.home")
+                            + uriString.substring(index + 2);
+                }
+            }
+
+            // Recreate the URI if needed
+            uri = new URI(uriString);
+
+            // First check if this URI is cached, if it is then we're done
+            cacheEntry = LocatorCache.locatorCache().fetchURICache(uri);
+            if (null != cacheEntry) {
+                // Cache hit! Grab contentType and contentLength and be done
+                contentType = cacheEntry.getMIMEType();
+                contentLength = cacheEntry.getBuffer().capacity();