diff --git a/README.md b/README.md
index a6c0ed3f..4b718c34 100644
--- a/README.md
+++ b/README.md
@@ -80,6 +80,59 @@ Under `.addPackage(new MainReactPackage())`:
.addPackage(new ReactVideoPackage())
```
+#### Windows
+
+Make the following additions to the given files manually:
+
+**windows/myapp.sln**
+
+Add the `ReactNativeVideo` project to your solution.
+1. Open the solution in Visual Studio 2015
+2. Right-click Solution icon in Solution Explorer > Add > Existing Project...
+3. Select `node_modules\react-native-video\windows\ReactNativeVideo\ReactNativeVideo.csproj`
+
+**windows/myapp/myapp.csproj**
+
+Add a reference to `ReactNativeVideo` to your main application project.
+
+Using Visual Studio 2015:
+1. Right-click main application project > Add > Reference...
+2. Check `ReactNativeVideo` from Solution Projects.
+
+Manually from `windows/myapp/myapp.csproj`, add:
+```xml
+
+ {e8f5f57f-757e-4237-ad23-f7a8755427cd}
+ ReactNativeVideo
+
+```
+
+**MainPage.cs**
+
+Add the `ReactVideoPackage` class to your list of exported packages.
+```cs
+using ReactNative;
+using ReactNative.Modules.Core;
+using ReactNative.Shell;
+using ReactNativeVideo; // <-- Add this
+using System.Collections.Generic;
+...
+
+ public override List Packages
+ {
+ get
+ {
+ return new List
+ {
+ new MainReactPackage(),
+ new ReactVideoPackage(), // <-- Add this
+ };
+ }
+ }
+
+...
+```
+
## Usage
```javascript
diff --git a/Video.js b/Video.js
index 3c032f74..d5281523 100644
--- a/Video.js
+++ b/Video.js
@@ -125,7 +125,7 @@ export default class Video extends Component {
}
const isNetwork = !!(uri && uri.match(/^https?:/));
- const isAsset = !!(uri && uri.match(/^(assets-library|file|content):/));
+ const isAsset = !!(uri && uri.match(/^(assets-library|file|content|ms-appx|ms-appdata):/));
let nativeResizeMode;
if (resizeMode === VideoResizeMode.stretch) {
diff --git a/example/index.windows.js b/example/index.windows.js
new file mode 100644
index 00000000..a3d21c6f
--- /dev/null
+++ b/example/index.windows.js
@@ -0,0 +1,210 @@
+'use strict';
+
+import React, {
+ Component
+} from 'react';
+
+import {
+ AppRegistry,
+ StyleSheet,
+ Text,
+ TouchableOpacity,
+ View,
+} from 'react-native';
+
+import Video from 'react-native-video';
+
+class VideoPlayer extends Component {
+ constructor(props) {
+ super(props);
+ this.onLoad = this.onLoad.bind(this);
+ this.onProgress = this.onProgress.bind(this);
+ }
+
+ state = {
+ rate: 1,
+ volume: 1,
+ muted: false,
+ resizeMode: 'contain',
+ duration: 0.0,
+ currentTime: 0.0,
+ };
+
+ onLoad(data) {
+ this.setState({duration: data.duration});
+ }
+
+ onProgress(data) {
+ this.setState({currentTime: data.currentTime});
+ }
+
+ getCurrentTimePercentage() {
+ if (this.state.currentTime > 0) {
+ return parseFloat(this.state.currentTime) / parseFloat(this.state.duration);
+ } else {
+ return 0;
+ }
+ }
+
+ renderRateControl(rate) {
+ const isSelected = (this.state.rate == rate);
+
+ return (
+ { this.setState({rate: rate}) }}>
+
+ {rate}x
+
+
+ )
+ }
+
+ renderResizeModeControl(resizeMode) {
+ const isSelected = (this.state.resizeMode == resizeMode);
+
+ return (
+ { this.setState({resizeMode: resizeMode}) }}>
+
+ {resizeMode}
+
+
+ )
+ }
+
+ renderVolumeControl(volume) {
+ const isSelected = (this.state.volume == volume);
+
+ return (
+ { this.setState({volume: volume}) }}>
+
+ {volume * 100}%
+
+
+ )
+ }
+
+ render() {
+ const flexCompleted = this.getCurrentTimePercentage() * 100;
+ const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100;
+
+ return (
+
+ {this.setState({paused: !this.state.paused})}}>
+
+
+
+
+
+ {this.renderRateControl(0.25)}
+ {this.renderRateControl(0.5)}
+ {this.renderRateControl(1.0)}
+ {this.renderRateControl(1.5)}
+ {this.renderRateControl(2.0)}
+
+
+
+ {this.renderVolumeControl(0.5)}
+ {this.renderVolumeControl(1)}
+ {this.renderVolumeControl(1.5)}
+
+
+
+ {this.renderResizeModeControl('cover')}
+ {this.renderResizeModeControl('contain')}
+ {this.renderResizeModeControl('stretch')}
+
+
+
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ backgroundColor: 'black',
+ },
+ fullScreen: {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ bottom: 0,
+ right: 0,
+ },
+ controls: {
+ backgroundColor: "transparent",
+ borderRadius: 5,
+ position: 'absolute',
+ bottom: 20,
+ left: 20,
+ right: 20,
+ },
+ progress: {
+ flex: 1,
+ flexDirection: 'row',
+ borderRadius: 3,
+ overflow: 'hidden',
+ },
+ innerProgressCompleted: {
+ height: 20,
+ backgroundColor: '#cccccc',
+ },
+ innerProgressRemaining: {
+ height: 20,
+ backgroundColor: '#2C2C2C',
+ },
+ generalControls: {
+ flex: 1,
+ flexDirection: 'row',
+ borderRadius: 4,
+ overflow: 'hidden',
+ paddingBottom: 10,
+ },
+ rateControl: {
+ flex: 1,
+ flexDirection: 'row',
+ justifyContent: 'center',
+ },
+ volumeControl: {
+ flex: 1,
+ flexDirection: 'row',
+ justifyContent: 'center',
+ },
+ resizeModeControl: {
+ flex: 1,
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ controlOption: {
+ alignSelf: 'center',
+ fontSize: 11,
+ color: "white",
+ paddingLeft: 2,
+ paddingRight: 2,
+ lineHeight: 12,
+ },
+});
+
+AppRegistry.registerComponent('VideoPlayer', () => VideoPlayer);
diff --git a/example/package.json b/example/package.json
index 0dcf72d8..a620fb4e 100644
--- a/example/package.json
+++ b/example/package.json
@@ -8,6 +8,10 @@
"dependencies": {
"react": "15.3.1",
"react-native": "^0.33.0",
- "react-native-video": "file:../"
+ "react-native-video": "file:../",
+ "react-native-windows": "^0.33.4"
+ },
+ "devDependencies": {
+ "rnpm-plugin-windows": "^0.2.3"
}
}
diff --git a/example/windows/.gitignore b/example/windows/.gitignore
new file mode 100644
index 00000000..33d3fde2
--- /dev/null
+++ b/example/windows/.gitignore
@@ -0,0 +1,89 @@
+*AppPackages*
+*BundleArtifacts*
+*ReactAssets*
+
+#OS junk files
+[Tt]humbs.db
+*.DS_Store
+
+#Visual Studio files
+*.[Oo]bj
+*.user
+*.aps
+*.pch
+*.vspscc
+*.vssscc
+*_i.c
+*_p.c
+*.ncb
+*.suo
+*.tlb
+*.tlh
+*.bak
+*.[Cc]ache
+*.ilk
+*.log
+*.lib
+*.sbr
+*.sdf
+*.opensdf
+*.opendb
+*.unsuccessfulbuild
+ipch/
+[Oo]bj/
+[Bb]in
+[Dd]ebug*/
+[Rr]elease*/
+Ankh.NoLoad
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+#MonoDevelop
+*.pidb
+*.userprefs
+
+#Tooling
+_ReSharper*/
+*.resharper
+[Tt]est[Rr]esult*
+*.sass-cache
+
+#Project files
+[Bb]uild/
+
+#Subversion files
+.svn
+
+# Office Temp Files
+~$*
+
+# vim Temp Files
+*~
+
+#NuGet
+packages/
+*.nupkg
+
+#ncrunch
+*ncrunch*
+*crunch*.local.xml
+
+# visual studio database projects
+*.dbmdl
+
+#Test files
+*.testsettings
+
+#Other files
+*.DotSettings
+.vs/
+*project.lock.json
diff --git a/example/windows/VideoPlayer.sln b/example/windows/VideoPlayer.sln
new file mode 100644
index 00000000..3d10db9e
--- /dev/null
+++ b/example/windows/VideoPlayer.sln
@@ -0,0 +1,141 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoPlayer", "VideoPlayer\VideoPlayer.csproj", "{A027BE54-D118-49A4-8D84-0666A2A93E64}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactNative", "..\node_modules\react-native-windows\ReactWindows\ReactNative\ReactNative.csproj", "{C7673AD5-E3AA-468C-A5FD-FA38154E205C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ChakraBridge", "..\node_modules\react-native-windows\ReactWindows\ChakraBridge\ChakraBridge.vcxproj", "{4B72C796-16D5-4E3A-81C0-3E36F531E578}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReactNativeVideo", "..\node_modules\react-native-video\windows\ReactNativeVideo\ReactNativeVideo.csproj", "{E8F5F57F-757E-4237-AD23-F7A8755427CD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ DebugBundle|ARM = DebugBundle|ARM
+ DebugBundle|x64 = DebugBundle|x64
+ DebugBundle|x86 = DebugBundle|x86
+ Release|ARM = Release|ARM
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ ReleaseBundle|ARM = ReleaseBundle|ARM
+ ReleaseBundle|x64 = ReleaseBundle|x64
+ ReleaseBundle|x86 = ReleaseBundle|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Debug|ARM.ActiveCfg = Debug|ARM
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Debug|ARM.Build.0 = Debug|ARM
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Debug|ARM.Deploy.0 = Debug|ARM
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Debug|x64.ActiveCfg = Debug|x64
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Debug|x64.Build.0 = Debug|x64
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Debug|x64.Deploy.0 = Debug|x64
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Debug|x86.ActiveCfg = Debug|x86
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Debug|x86.Build.0 = Debug|x86
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Debug|x86.Deploy.0 = Debug|x86
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.DebugBundle|ARM.ActiveCfg = DebugBundle|ARM
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.DebugBundle|ARM.Build.0 = DebugBundle|ARM
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.DebugBundle|ARM.Deploy.0 = DebugBundle|ARM
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.DebugBundle|x64.ActiveCfg = DebugBundle|x64
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.DebugBundle|x64.Build.0 = DebugBundle|x64
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.DebugBundle|x64.Deploy.0 = DebugBundle|x64
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.DebugBundle|x86.ActiveCfg = DebugBundle|x86
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.DebugBundle|x86.Build.0 = DebugBundle|x86
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.DebugBundle|x86.Deploy.0 = DebugBundle|x86
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Release|ARM.ActiveCfg = Release|ARM
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Release|ARM.Build.0 = Release|ARM
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Release|ARM.Deploy.0 = Release|ARM
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Release|x64.ActiveCfg = Release|x64
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Release|x64.Build.0 = Release|x64
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Release|x64.Deploy.0 = Release|x64
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Release|x86.ActiveCfg = Release|x86
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Release|x86.Build.0 = Release|x86
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.Release|x86.Deploy.0 = Release|x86
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.ReleaseBundle|ARM.ActiveCfg = ReleaseBundle|ARM
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.ReleaseBundle|ARM.Build.0 = ReleaseBundle|ARM
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.ReleaseBundle|ARM.Deploy.0 = ReleaseBundle|ARM
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.ReleaseBundle|x64.ActiveCfg = ReleaseBundle|x64
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.ReleaseBundle|x64.Build.0 = ReleaseBundle|x64
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.ReleaseBundle|x64.Deploy.0 = ReleaseBundle|x64
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.ReleaseBundle|x86.ActiveCfg = ReleaseBundle|x86
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.ReleaseBundle|x86.Build.0 = ReleaseBundle|x86
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}.ReleaseBundle|x86.Deploy.0 = ReleaseBundle|x86
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|ARM.ActiveCfg = Debug|ARM
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|ARM.Build.0 = Debug|ARM
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|x64.ActiveCfg = Debug|x64
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|x64.Build.0 = Debug|x64
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|x86.ActiveCfg = Debug|x86
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Debug|x86.Build.0 = Debug|x86
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.DebugBundle|ARM.ActiveCfg = Debug|ARM
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.DebugBundle|ARM.Build.0 = Debug|ARM
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.DebugBundle|x64.ActiveCfg = Debug|x64
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.DebugBundle|x64.Build.0 = Debug|x64
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.DebugBundle|x86.ActiveCfg = Debug|x86
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.DebugBundle|x86.Build.0 = Debug|x86
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|ARM.ActiveCfg = Release|ARM
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|ARM.Build.0 = Release|ARM
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|x64.ActiveCfg = Release|x64
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|x64.Build.0 = Release|x64
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|x86.ActiveCfg = Release|x86
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.Release|x86.Build.0 = Release|x86
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.ReleaseBundle|ARM.ActiveCfg = Release|ARM
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.ReleaseBundle|ARM.Build.0 = Release|ARM
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.ReleaseBundle|x64.ActiveCfg = Release|x64
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.ReleaseBundle|x64.Build.0 = Release|x64
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.ReleaseBundle|x86.ActiveCfg = Release|x86
+ {C7673AD5-E3AA-468C-A5FD-FA38154E205C}.ReleaseBundle|x86.Build.0 = Release|x86
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|ARM.ActiveCfg = Debug|ARM
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|ARM.Build.0 = Debug|ARM
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|x64.ActiveCfg = Debug|x64
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|x64.Build.0 = Debug|x64
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|x86.ActiveCfg = Debug|Win32
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Debug|x86.Build.0 = Debug|Win32
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.DebugBundle|ARM.ActiveCfg = Debug|ARM
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.DebugBundle|ARM.Build.0 = Debug|ARM
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.DebugBundle|x64.ActiveCfg = Debug|x64
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.DebugBundle|x64.Build.0 = Debug|x64
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.DebugBundle|x86.ActiveCfg = Debug|Win32
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.DebugBundle|x86.Build.0 = Debug|Win32
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|ARM.ActiveCfg = Release|ARM
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|ARM.Build.0 = Release|ARM
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|x64.ActiveCfg = Release|x64
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|x64.Build.0 = Release|x64
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|x86.ActiveCfg = Release|Win32
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.Release|x86.Build.0 = Release|Win32
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.ReleaseBundle|ARM.ActiveCfg = Release|ARM
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.ReleaseBundle|ARM.Build.0 = Release|ARM
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.ReleaseBundle|x64.ActiveCfg = Release|x64
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.ReleaseBundle|x64.Build.0 = Release|x64
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.ReleaseBundle|x86.ActiveCfg = Release|Win32
+ {4B72C796-16D5-4E3A-81C0-3E36F531E578}.ReleaseBundle|x86.Build.0 = Release|Win32
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.Debug|ARM.ActiveCfg = Debug|ARM
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.Debug|ARM.Build.0 = Debug|ARM
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.Debug|x64.ActiveCfg = Debug|x64
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.Debug|x64.Build.0 = Debug|x64
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.Debug|x86.ActiveCfg = Debug|x86
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.Debug|x86.Build.0 = Debug|x86
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.DebugBundle|ARM.ActiveCfg = Debug|ARM
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.DebugBundle|ARM.Build.0 = Debug|ARM
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.DebugBundle|x64.ActiveCfg = Debug|x64
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.DebugBundle|x64.Build.0 = Debug|x64
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.DebugBundle|x86.ActiveCfg = Debug|x86
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.DebugBundle|x86.Build.0 = Debug|x86
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.Release|ARM.ActiveCfg = Release|ARM
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.Release|ARM.Build.0 = Release|ARM
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.Release|x64.ActiveCfg = Release|x64
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.Release|x64.Build.0 = Release|x64
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.Release|x86.ActiveCfg = Release|x86
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.Release|x86.Build.0 = Release|x86
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.ReleaseBundle|ARM.ActiveCfg = Release|ARM
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.ReleaseBundle|ARM.Build.0 = Release|ARM
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.ReleaseBundle|x64.ActiveCfg = Release|x64
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.ReleaseBundle|x64.Build.0 = Release|x64
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.ReleaseBundle|x86.ActiveCfg = Release|x86
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}.ReleaseBundle|x86.Build.0 = Release|x86
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/example/windows/VideoPlayer/App.xaml b/example/windows/VideoPlayer/App.xaml
new file mode 100644
index 00000000..02a3efbb
--- /dev/null
+++ b/example/windows/VideoPlayer/App.xaml
@@ -0,0 +1,8 @@
+
+
+
diff --git a/example/windows/VideoPlayer/App.xaml.cs b/example/windows/VideoPlayer/App.xaml.cs
new file mode 100644
index 00000000..491a7ce5
--- /dev/null
+++ b/example/windows/VideoPlayer/App.xaml.cs
@@ -0,0 +1,112 @@
+using ReactNative;
+using System;
+using Windows.ApplicationModel;
+using Windows.ApplicationModel.Activation;
+using Windows.UI.Core;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Navigation;
+
+namespace VideoPlayer
+{
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ sealed partial class App : Application
+ {
+ private readonly ReactPage _reactPage;
+
+ ///
+ /// Initializes the singleton application object. This is the first line of authored code
+ /// executed, and as such is the logical equivalent of main() or WinMain().
+ ///
+ public App()
+ {
+ this.InitializeComponent();
+ this.Suspending += OnSuspending;
+ this.Resuming += OnResuming;
+
+ _reactPage = new MainPage();
+ }
+
+ ///
+ /// Invoked when the application is launched normally by the end user. Other entry points
+ /// will be used such as when the application is launched to open a specific file.
+ ///
+ /// Details about the launch request and process.
+ protected override void OnLaunched(LaunchActivatedEventArgs e)
+ {
+ _reactPage.OnResume(Exit);
+
+#if DEBUG
+ if (System.Diagnostics.Debugger.IsAttached)
+ {
+ this.DebugSettings.EnableFrameRateCounter = true;
+ }
+
+ SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
+ AppViewBackButtonVisibility.Visible;
+#endif
+
+ Frame rootFrame = Window.Current.Content as Frame;
+
+ // Do not repeat app initialization when the Window already has content,
+ // just ensure that the window is active
+ if (rootFrame == null)
+ {
+ _reactPage.OnCreate(e.Arguments);
+
+ // Create a Frame to act as the navigation context and navigate to the first page
+ rootFrame = new Frame();
+
+ rootFrame.NavigationFailed += OnNavigationFailed;
+
+ // Place the frame in the current Window
+ Window.Current.Content = rootFrame;
+ }
+
+ if (rootFrame.Content == null)
+ {
+ // When the navigation stack isn't restored navigate to the first page,
+ // configuring the new page by passing required information as a navigation
+ // parameter
+ rootFrame.Content = _reactPage;
+ }
+
+ // Ensure the current window is active
+ Window.Current.Activate();
+ }
+
+ ///
+ /// Invoked when Navigation to a certain page fails
+ ///
+ /// The Frame which failed navigation
+ /// Details about the navigation failure
+ void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
+ {
+ throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
+ }
+
+ ///
+ /// Invoked when application execution is being suspended. Application state is saved
+ /// without knowing whether the application will be terminated or resumed with the contents
+ /// of memory still intact.
+ ///
+ /// The source of the suspend request.
+ /// Details about the suspend request.
+ private void OnSuspending(object sender, SuspendingEventArgs e)
+ {
+ _reactPage.OnSuspend();
+ }
+
+ ///
+ /// Invoked when application execution is being resumed.
+ ///
+ /// The source of the resume request.
+ /// Details about the resume request.
+ private void OnResuming(object sender, object e)
+ {
+ _reactPage.OnResume(Exit);
+ }
+ }
+}
diff --git a/example/windows/VideoPlayer/Assets/LockScreenLogo.scale-200.png b/example/windows/VideoPlayer/Assets/LockScreenLogo.scale-200.png
new file mode 100644
index 00000000..735f57ad
Binary files /dev/null and b/example/windows/VideoPlayer/Assets/LockScreenLogo.scale-200.png differ
diff --git a/example/windows/VideoPlayer/Assets/SplashScreen.scale-200.png b/example/windows/VideoPlayer/Assets/SplashScreen.scale-200.png
new file mode 100644
index 00000000..023e7f1f
Binary files /dev/null and b/example/windows/VideoPlayer/Assets/SplashScreen.scale-200.png differ
diff --git a/example/windows/VideoPlayer/Assets/Square150x150Logo.scale-200.png b/example/windows/VideoPlayer/Assets/Square150x150Logo.scale-200.png
new file mode 100644
index 00000000..af49fec1
Binary files /dev/null and b/example/windows/VideoPlayer/Assets/Square150x150Logo.scale-200.png differ
diff --git a/example/windows/VideoPlayer/Assets/Square44x44Logo.scale-200.png b/example/windows/VideoPlayer/Assets/Square44x44Logo.scale-200.png
new file mode 100644
index 00000000..ce342a2e
Binary files /dev/null and b/example/windows/VideoPlayer/Assets/Square44x44Logo.scale-200.png differ
diff --git a/example/windows/VideoPlayer/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/example/windows/VideoPlayer/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
new file mode 100644
index 00000000..f6c02ce9
Binary files /dev/null and b/example/windows/VideoPlayer/Assets/Square44x44Logo.targetsize-24_altform-unplated.png differ
diff --git a/example/windows/VideoPlayer/Assets/StoreLogo.png b/example/windows/VideoPlayer/Assets/StoreLogo.png
new file mode 100644
index 00000000..7385b56c
Binary files /dev/null and b/example/windows/VideoPlayer/Assets/StoreLogo.png differ
diff --git a/example/windows/VideoPlayer/Assets/Wide310x150Logo.scale-200.png b/example/windows/VideoPlayer/Assets/Wide310x150Logo.scale-200.png
new file mode 100644
index 00000000..288995b3
Binary files /dev/null and b/example/windows/VideoPlayer/Assets/Wide310x150Logo.scale-200.png differ
diff --git a/example/windows/VideoPlayer/MainPage.cs b/example/windows/VideoPlayer/MainPage.cs
new file mode 100644
index 00000000..4db71186
--- /dev/null
+++ b/example/windows/VideoPlayer/MainPage.cs
@@ -0,0 +1,55 @@
+using ReactNative;
+using ReactNative.Modules.Core;
+using ReactNative.Shell;
+using ReactNativeVideo;
+using System.Collections.Generic;
+using Windows.UI.Xaml.Media.Imaging;
+
+namespace VideoPlayer
+{
+ class MainPage : ReactPage
+ {
+ public override string MainComponentName
+ {
+ get
+ {
+ return "VideoPlayer";
+ }
+ }
+
+#if BUNDLE
+ public override string JavaScriptBundleFile
+ {
+ get
+ {
+ return "ms-appx:///ReactAssets/index.windows.bundle";
+ }
+ }
+#endif
+
+ public override List Packages
+ {
+ get
+ {
+ return new List
+ {
+ new MainReactPackage(),
+ new ReactVideoPackage(),
+ };
+ }
+ }
+
+ public override bool UseDeveloperSupport
+ {
+ get
+ {
+#if !BUNDLE || DEBUG
+ return true;
+#else
+ return false;
+#endif
+ }
+ }
+ }
+
+}
diff --git a/example/windows/VideoPlayer/Package.appxmanifest b/example/windows/VideoPlayer/Package.appxmanifest
new file mode 100644
index 00000000..be303ca5
--- /dev/null
+++ b/example/windows/VideoPlayer/Package.appxmanifest
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+ VideoPlayer
+ React Native for UWP
+ Assets\StoreLogo.png
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/windows/VideoPlayer/Properties/AssemblyInfo.cs b/example/windows/VideoPlayer/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..cb6ff6b7
--- /dev/null
+++ b/example/windows/VideoPlayer/Properties/AssemblyInfo.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("VideoPlayer")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("VideoPlayer")]
+[assembly: AssemblyCopyright("Copyright © 2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: ComVisible(false)]
\ No newline at end of file
diff --git a/example/windows/VideoPlayer/Properties/Default.rd.xml b/example/windows/VideoPlayer/Properties/Default.rd.xml
new file mode 100644
index 00000000..86952373
--- /dev/null
+++ b/example/windows/VideoPlayer/Properties/Default.rd.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/example/windows/VideoPlayer/VideoPlayer.csproj b/example/windows/VideoPlayer/VideoPlayer.csproj
new file mode 100644
index 00000000..96611032
--- /dev/null
+++ b/example/windows/VideoPlayer/VideoPlayer.csproj
@@ -0,0 +1,230 @@
+
+
+
+
+ Debug
+ x86
+ {A027BE54-D118-49A4-8D84-0666A2A93E64}
+ AppContainerExe
+ Properties
+ VideoPlayer
+ VideoPlayer
+ en-US
+ UAP
+ 10.0.14393.0
+ 10.0.10586.0
+ 14
+ 512
+ {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ VideoPlayer_TemporaryKey.pfx
+
+
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ x86
+ false
+ prompt
+ true
+
+
+ true
+ bin\x86\DebugBundle\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS;BUNDLE
+ ;2008
+ true
+ full
+ x86
+ false
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ x86
+ false
+ prompt
+ true
+ true
+
+
+ bin\x86\ReleaseBundle\
+ TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS;BUNDLE
+ true
+ ;2008
+ true
+ pdbonly
+ x86
+ false
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+ true
+
+
+ true
+ bin\ARM\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ ARM
+ false
+ prompt
+ true
+
+
+ true
+ bin\ARM\DebugBundle\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS;BUNDLE
+ ;2008
+ true
+ full
+ ARM
+ false
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\ARM\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ ARM
+ false
+ prompt
+ true
+ true
+
+
+ bin\ARM\ReleaseBundle\
+ TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS;BUNDLE
+ true
+ ;2008
+ true
+ pdbonly
+ ARM
+ false
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+ true
+
+
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ x64
+ false
+ prompt
+ true
+
+
+ true
+ bin\x64\DebugBundle\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS;BUNDLE
+ ;2008
+ true
+ full
+ x64
+ false
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ x64
+ false
+ prompt
+ true
+ true
+
+
+ bin\x64\ReleaseBundle\
+ TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS;BUNDLE
+ true
+ ;2008
+ true
+ pdbonly
+ x64
+ false
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+ true
+
+
+
+
+
+
+
+ App.xaml
+
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ MSBuild:Compile
+ Designer
+
+
+
+
+ {e8f5f57f-757e-4237-ad23-f7a8755427cd}
+ ReactNativeVideo
+
+
+ {c7673ad5-e3aa-468c-a5fd-fa38154e205c}
+ ReactNative
+
+
+
+
+ PreserveNewest
+
+
+
+ 14.0
+
+
+
+
\ No newline at end of file
diff --git a/example/windows/VideoPlayer/VideoPlayer_TemporaryKey.pfx b/example/windows/VideoPlayer/VideoPlayer_TemporaryKey.pfx
new file mode 100644
index 00000000..08328fc1
Binary files /dev/null and b/example/windows/VideoPlayer/VideoPlayer_TemporaryKey.pfx differ
diff --git a/example/windows/VideoPlayer/project.json b/example/windows/VideoPlayer/project.json
new file mode 100644
index 00000000..bf00b26b
--- /dev/null
+++ b/example/windows/VideoPlayer/project.json
@@ -0,0 +1,17 @@
+{
+ "dependencies": {
+ "Facebook.CSSLayout": "2.0.1-pre",
+ "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2"
+ },
+ "frameworks": {
+ "uap10.0": {}
+ },
+ "runtimes": {
+ "win10-arm": {},
+ "win10-arm-aot": {},
+ "win10-x86": {},
+ "win10-x86-aot": {},
+ "win10-x64": {},
+ "win10-x64-aot": {}
+ }
+}
\ No newline at end of file
diff --git a/windows/.gitignore b/windows/.gitignore
new file mode 100644
index 00000000..74236826
--- /dev/null
+++ b/windows/.gitignore
@@ -0,0 +1,97 @@
+#Visual Studio files
+*.[Oo]bj
+*.user
+*.aps
+*.pch
+*.vspscc
+*.vssscc
+*_i.c
+*_p.c
+*.ncb
+*.suo
+*.tlb
+*.tlh
+*.tlog
+*.bak
+*.[Cc]ache
+*.ilk
+*.log
+*.lib
+*.sbr
+*.sdf
+*.opensdf
+*.opendb
+*.unsuccessfulbuild
+*.lastbuildstate
+ipch/
+[Oo]bj/
+[Bb]in
+[Dd]ebug*/
+[Rr]elease*/
+*.tlog/
+Ankh.NoLoad
+UpgradeLog.htm
+
+#MonoDevelop
+*.pidb
+*.userprefs
+
+#Tooling
+_ReSharper*/
+*.resharper
+[Tt]est[Rr]esult*
+*.sass-cache
+
+#Project files
+[Bb]uild/
+
+#Subversion files
+.svn
+
+# Office Temp Files
+~$*
+
+# vim Temp Files
+*~
+
+#NuGet
+packages/
+*.nupkg
+
+#ncrunch
+*ncrunch*
+*crunch*.local.xml
+
+# visual studio database projects
+*.dbmdl
+
+#Test files
+*.testsettings
+
+#Other files
+*.DotSettings
+.vs/
+.vscode/
+*project.lock.json
+
+#JavaScript files
+*.jsbundle
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Build results
+[Dd]ebugPublic/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Ll]og/
diff --git a/windows/ReactNativeVideo/Properties/AssemblyInfo.cs b/windows/ReactNativeVideo/Properties/AssemblyInfo.cs
new file mode 100644
index 00000000..1d4241b5
--- /dev/null
+++ b/windows/ReactNativeVideo/Properties/AssemblyInfo.cs
@@ -0,0 +1,29 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("ReactNativeVideo")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("ReactNativeVideo")]
+[assembly: AssemblyCopyright("Copyright © 2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: ComVisible(false)]
\ No newline at end of file
diff --git a/windows/ReactNativeVideo/Properties/ReactNativeVideo.rd.xml b/windows/ReactNativeVideo/Properties/ReactNativeVideo.rd.xml
new file mode 100644
index 00000000..19ad73b1
--- /dev/null
+++ b/windows/ReactNativeVideo/Properties/ReactNativeVideo.rd.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
diff --git a/windows/ReactNativeVideo/ReactNativeVideo.csproj b/windows/ReactNativeVideo/ReactNativeVideo.csproj
new file mode 100644
index 00000000..8ed6402e
--- /dev/null
+++ b/windows/ReactNativeVideo/ReactNativeVideo.csproj
@@ -0,0 +1,116 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {E8F5F57F-757E-4237-AD23-F7A8755427CD}
+ Library
+ Properties
+ ReactNativeVideo
+ ReactNativeVideo
+ en-US
+ UAP
+ 10.0.14393.0
+ 10.0.10586.0
+ 14
+ 512
+ {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+
+
+ x86
+ true
+ bin\x86\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ x86
+ false
+ prompt
+
+
+ x86
+ bin\x86\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ x86
+ false
+ prompt
+
+
+ ARM
+ true
+ bin\ARM\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ ARM
+ false
+ prompt
+
+
+ ARM
+ bin\ARM\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ ARM
+ false
+ prompt
+
+
+ x64
+ true
+ bin\x64\Debug\
+ DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
+ ;2008
+ full
+ x64
+ false
+ prompt
+
+
+ x64
+ bin\x64\Release\
+ TRACE;NETFX_CORE;WINDOWS_UWP
+ true
+ ;2008
+ pdbonly
+ x64
+ false
+ prompt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {c7673ad5-e3aa-468c-a5fd-fa38154e205c}
+ ReactNative
+
+
+
+ 14.0
+
+
+
+
\ No newline at end of file
diff --git a/windows/ReactNativeVideo/ReactVideoEventType.cs b/windows/ReactNativeVideo/ReactVideoEventType.cs
new file mode 100644
index 00000000..dd3f3feb
--- /dev/null
+++ b/windows/ReactNativeVideo/ReactVideoEventType.cs
@@ -0,0 +1,15 @@
+namespace ReactNativeVideo
+{
+ enum ReactVideoEventType
+ {
+ LoadStart,
+ Load,
+ Error,
+ Progress,
+ Seek,
+ End,
+ Stalled,
+ Resume,
+ ReadyForDisplay,
+ }
+}
diff --git a/windows/ReactNativeVideo/ReactVideoEventTypeExtensions.cs b/windows/ReactNativeVideo/ReactVideoEventTypeExtensions.cs
new file mode 100644
index 00000000..5f2b63db
--- /dev/null
+++ b/windows/ReactNativeVideo/ReactVideoEventTypeExtensions.cs
@@ -0,0 +1,36 @@
+using System;
+using static System.FormattableString;
+
+namespace ReactNativeVideo
+{
+ static class ReactVideoEventTypeExtensions
+ {
+ public static string GetEventName(this ReactVideoEventType eventType)
+ {
+ switch (eventType)
+ {
+ case ReactVideoEventType.LoadStart:
+ return "onVideoLoadStart";
+ case ReactVideoEventType.Load:
+ return "onVideoLoad";
+ case ReactVideoEventType.Error:
+ return "onVideoError";
+ case ReactVideoEventType.Progress:
+ return "onVideoProgress";
+ case ReactVideoEventType.Seek:
+ return "onVideoSeek";
+ case ReactVideoEventType.End:
+ return "onVideoEnd";
+ case ReactVideoEventType.Stalled:
+ return "onPlaybackStalled";
+ case ReactVideoEventType.Resume:
+ return "onPlaybackResume";
+ case ReactVideoEventType.ReadyForDisplay:
+ return "onReadyForDisplay";
+ default:
+ throw new NotSupportedException(
+ Invariant($"No event name added for event type '{eventType}'."));
+ }
+ }
+ }
+}
diff --git a/windows/ReactNativeVideo/ReactVideoPackage.cs b/windows/ReactNativeVideo/ReactVideoPackage.cs
new file mode 100644
index 00000000..b8cc654b
--- /dev/null
+++ b/windows/ReactNativeVideo/ReactVideoPackage.cs
@@ -0,0 +1,30 @@
+using ReactNative.Bridge;
+using ReactNative.Modules.Core;
+using ReactNative.UIManager;
+using System;
+using System.Collections.Generic;
+
+namespace ReactNativeVideo
+{
+ public class ReactVideoPackage : IReactPackage
+ {
+ public IReadOnlyList CreateJavaScriptModulesConfig()
+ {
+ return Array.Empty();
+ }
+
+ public IReadOnlyList CreateNativeModules(ReactContext reactContext)
+ {
+ return Array.Empty();
+
+ }
+
+ public IReadOnlyList CreateViewManagers(ReactContext reactContext)
+ {
+ return new List
+ {
+ new ReactVideoViewManager(),
+ };
+ }
+ }
+}
diff --git a/windows/ReactNativeVideo/ReactVideoView.cs b/windows/ReactNativeVideo/ReactVideoView.cs
new file mode 100644
index 00000000..2e02bf67
--- /dev/null
+++ b/windows/ReactNativeVideo/ReactVideoView.cs
@@ -0,0 +1,355 @@
+using Newtonsoft.Json.Linq;
+using ReactNative.UIManager;
+using ReactNative.UIManager.Events;
+using System;
+using Windows.ApplicationModel.Core;
+using Windows.Media.Core;
+using Windows.Media.Playback;
+using Windows.UI.Core;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+
+namespace ReactNativeVideo
+{
+ class ReactVideoView : MediaPlayerElement, IDisposable
+ {
+ public const string EVENT_PROP_SEEK_TIME = "seekTime";
+
+ private readonly DispatcherTimer _timer;
+
+ private bool _isSourceSet;
+
+ private string _uri;
+ private bool _isLoopingEnabled;
+ private bool _isPaused;
+ private bool _isMuted;
+ private bool _isUserControlEnabled;
+ private bool _isCompleted;
+ private double _volume;
+ private double _rate;
+
+ public ReactVideoView()
+ {
+ _timer = new DispatcherTimer();
+ _timer.Interval = TimeSpan.FromMilliseconds(250.0);
+ _timer.Start();
+ }
+
+ public new string Source
+ {
+ set
+ {
+ _uri = value;
+ base.Source = MediaSource.CreateFromUri(new Uri(_uri));
+ _isSourceSet = true;
+ ApplyModifiers();
+ SubscribeEvents();
+ }
+ }
+
+ public bool IsLoopingEnabled
+ {
+ set
+ {
+ _isLoopingEnabled = value;
+ if (_isSourceSet)
+ {
+ MediaPlayer.IsLoopingEnabled = _isLoopingEnabled;
+ }
+ }
+ }
+
+ public bool IsMuted
+ {
+ set
+ {
+ _isMuted = value;
+ if (_isSourceSet)
+ {
+ MediaPlayer.IsMuted = _isMuted;
+ }
+ }
+ }
+
+ public bool IsPaused
+ {
+ set
+ {
+ _isPaused = value;
+ if (_isSourceSet)
+ {
+ if (_isPaused)
+ {
+ MediaPlayer.Pause();
+ }
+ else
+ {
+ MediaPlayer.Play();
+ }
+ }
+ }
+ }
+
+ public bool IsUserControlEnabled
+ {
+ set
+ {
+ _isUserControlEnabled = value;
+ if (_isSourceSet)
+ {
+ MediaPlayer.SystemMediaTransportControls.IsEnabled = _isUserControlEnabled;
+ }
+ }
+ }
+
+ public double Volume
+ {
+ set
+ {
+ _volume = value;
+ if (_isSourceSet)
+ {
+ MediaPlayer.Volume = _volume;
+ }
+ }
+ }
+
+ public double Rate
+ {
+ set
+ {
+ _rate = value;
+ if (_isSourceSet)
+ {
+ MediaPlayer.PlaybackSession.PlaybackRate = _rate;
+ }
+ }
+ }
+
+ public double ProgressUpdateInterval
+ {
+ set
+ {
+ _timer.Interval = TimeSpan.FromSeconds(value);
+ }
+ }
+
+ public void Seek(double seek)
+ {
+ if (_isSourceSet)
+ {
+ MediaPlayer.PlaybackSession.Position = TimeSpan.FromSeconds(seek);
+ }
+ }
+
+ public void Dispose()
+ {
+ if (_isSourceSet)
+ {
+ _timer.Tick -= OnTick;
+ MediaPlayer.SourceChanged -= OnSourceChanged;
+ MediaPlayer.MediaOpened -= OnMediaOpened;
+ MediaPlayer.MediaFailed -= OnMediaFailed;
+ MediaPlayer.MediaEnded -= OnMediaEnded;
+ MediaPlayer.PlaybackSession.BufferingStarted -= OnBufferingStarted;
+ MediaPlayer.PlaybackSession.BufferingEnded -= OnBufferingEnded;
+ MediaPlayer.PlaybackSession.SeekCompleted -= OnSeekCompleted;
+ }
+
+ _timer.Stop();
+ }
+
+ private void ApplyModifiers()
+ {
+ IsLoopingEnabled = _isLoopingEnabled;
+ IsMuted = _isMuted;
+ IsPaused = _isPaused;
+ IsUserControlEnabled = _isUserControlEnabled;
+ Volume = _volume;
+ Rate = _rate;
+ }
+
+ private void SubscribeEvents()
+ {
+ _timer.Tick += OnTick;
+ MediaPlayer.SourceChanged += OnSourceChanged;
+ MediaPlayer.MediaOpened += OnMediaOpened;
+ MediaPlayer.MediaFailed += OnMediaFailed;
+ MediaPlayer.MediaEnded += OnMediaEnded;
+ MediaPlayer.PlaybackSession.BufferingStarted += OnBufferingStarted;
+ MediaPlayer.PlaybackSession.BufferingEnded += OnBufferingEnded;
+ MediaPlayer.PlaybackSession.SeekCompleted += OnSeekCompleted;
+ }
+
+ private void OnTick(object sender, object e)
+ {
+ if (_isSourceSet && !_isCompleted && !_isPaused)
+ {
+ this.GetReactContext()
+ .GetNativeModule()
+ .EventDispatcher
+ .DispatchEvent(
+ new ReactVideoEvent(
+ ReactVideoEventType.Progress.GetEventName(),
+ this.GetTag(),
+ new JObject
+ {
+ { "currentTime", MediaPlayer.PlaybackSession.Position.TotalSeconds },
+ { "playableDuration", 0.0 /* TODO */ }
+ }));
+ }
+ }
+
+ private void OnSourceChanged(MediaPlayer sender, object args)
+ {
+ this.GetReactContext()
+ .GetNativeModule()
+ .EventDispatcher
+ .DispatchEvent(
+ new ReactVideoEvent(
+ ReactVideoEventType.LoadStart.GetEventName(),
+ this.GetTag(),
+ new JObject
+ {
+ { "src", this._uri }
+ }));
+ }
+
+ private void OnMediaOpened(MediaPlayer sender, object args)
+ {
+ RunOnDispatcher(delegate
+ {
+ var width = MediaPlayer.PlaybackSession.NaturalVideoWidth;
+ var height = MediaPlayer.PlaybackSession.NaturalVideoHeight;
+ var orientation = (width > height) ? "landscape" : "portrait";
+ var size = new JObject
+ {
+ { "width", width },
+ { "height", height },
+ { "orientation", orientation }
+ };
+
+ this.GetReactContext().GetNativeModule().EventDispatcher.DispatchEvent(new ReactVideoView.ReactVideoEvent(ReactVideoEventType.Load.GetEventName(), this.GetTag(), new JObject
+ {
+ { "duration", MediaPlayer.PlaybackSession.NaturalDuration.TotalSeconds },
+ { "currentTime", MediaPlayer.PlaybackSession.Position.TotalSeconds },
+ { "naturalSize", size },
+ { "canPlayFastForward", false },
+ { "canPlaySlowForward", false },
+ { "canPlaySlow", false },
+ { "canPlayReverse", false },
+ { "canStepBackward", false },
+ { "canStepForward", false }
+ }));
+ });
+ }
+
+ private void OnMediaFailed(MediaPlayer sender, MediaPlayerFailedEventArgs args)
+ {
+ var errorData = new JObject
+ {
+ { "what", args.Error.ToString() },
+ { "extra", args.ErrorMessage }
+ };
+
+ this.GetReactContext()
+ .GetNativeModule()
+ .EventDispatcher
+ .DispatchEvent(
+ new ReactVideoEvent(
+ ReactVideoEventType.Error.GetEventName(),
+ this.GetTag(),
+ new JObject
+ {
+ { "error", errorData }
+ }));
+ }
+
+ private void OnMediaEnded(MediaPlayer sender, object args)
+ {
+ _isCompleted = true;
+ this.GetReactContext()
+ .GetNativeModule()
+ .EventDispatcher
+ .DispatchEvent(
+ new ReactVideoEvent(
+ ReactVideoEventType.End.GetEventName(),
+ this.GetTag(),
+ null));
+ }
+
+ private void OnBufferingStarted(MediaPlaybackSession sender, object args)
+ {
+ this.GetReactContext()
+ .GetNativeModule()
+ .EventDispatcher
+ .DispatchEvent(
+ new ReactVideoEvent(
+ ReactVideoEventType.Stalled.GetEventName(),
+ this.GetTag(),
+ new JObject()));
+ }
+
+ private void OnBufferingEnded(MediaPlaybackSession sender, object args)
+ {
+ this.GetReactContext()
+ .GetNativeModule()
+ .EventDispatcher
+ .DispatchEvent(
+ new ReactVideoEvent(
+ ReactVideoEventType.Resume.GetEventName(),
+ this.GetTag(),
+ new JObject()));
+ }
+
+ private void OnSeekCompleted(MediaPlaybackSession sender, object args)
+ {
+ this.GetReactContext()
+ .GetNativeModule()
+ .EventDispatcher.DispatchEvent(
+ new ReactVideoEvent(
+ ReactVideoEventType.Seek.GetEventName(),
+ this.GetTag(),
+ new JObject()));
+ }
+
+ private static async void RunOnDispatcher(DispatchedHandler action)
+ {
+ await CoreApplication.GetCurrentView().Dispatcher.RunAsync(CoreDispatcherPriority.Normal, action).AsTask().ConfigureAwait(false);
+ }
+
+ class ReactVideoEvent : Event
+ {
+ private readonly string _eventName;
+ private readonly JObject _eventData;
+
+ public ReactVideoEvent(string eventName, int viewTag, JObject eventData)
+ : base(viewTag, TimeSpan.FromTicks(Environment.TickCount))
+ {
+ _eventName = eventName;
+ _eventData = eventData;
+ }
+
+ public override string EventName
+ {
+ get
+ {
+ return _eventName;
+ }
+ }
+
+ public override bool CanCoalesce
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ public override void Dispatch(RCTEventEmitter eventEmitter)
+ {
+ eventEmitter.receiveEvent(ViewTag, EventName, _eventData);
+ }
+ }
+ }
+}
diff --git a/windows/ReactNativeVideo/ReactVideoViewManager.cs b/windows/ReactNativeVideo/ReactVideoViewManager.cs
new file mode 100644
index 00000000..e93456c3
--- /dev/null
+++ b/windows/ReactNativeVideo/ReactVideoViewManager.cs
@@ -0,0 +1,137 @@
+using Newtonsoft.Json.Linq;
+using ReactNative.UIManager;
+using ReactNative.UIManager.Annotations;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Media;
+
+namespace ReactNativeVideo
+{
+ class ReactVideoViewManager : SimpleViewManager
+ {
+ public override string Name
+ {
+ get
+ {
+ return "RCTVideo";
+ }
+ }
+
+ public override IReadOnlyDictionary ExportedViewConstants
+ {
+ get
+ {
+ return new Dictionary
+ {
+ { "ScaleNone", ((int)Stretch.None).ToString() },
+ { "ScaleToFill", ((int)Stretch.UniformToFill).ToString() },
+ { "ScaleAspectFit", ((int)Stretch.Uniform).ToString() },
+ { "ScaleAspectFill", ((int)Stretch.Fill).ToString() },
+ };
+ }
+ }
+
+ public override IReadOnlyDictionary ExportedCustomDirectEventTypeConstants
+ {
+ get
+ {
+ var events = new Dictionary();
+ var eventTypes = Enum.GetValues(typeof(ReactVideoEventType)).OfType();
+ foreach (var eventType in eventTypes)
+ {
+ events.Add(eventType.GetEventName(), new Dictionary
+ {
+ { "registrationName", eventType.GetEventName() },
+ });
+ }
+
+ return events;
+ }
+ }
+
+ [ReactProp("src")]
+ public void SetSource(ReactVideoView view, JObject source)
+ {
+ view.Source = source.Value("uri");
+ }
+
+ [ReactProp("resizeMode")]
+ public void SetResizeMode(ReactVideoView view, string resizeMode)
+ {
+ view.Stretch = (Stretch)int.Parse(resizeMode);
+ }
+
+ [ReactProp("repeat")]
+ public void SetRepeat(ReactVideoView view, bool repeat)
+ {
+ view.IsLoopingEnabled = repeat;
+ }
+
+ [ReactProp("paused")]
+ public void SetPaused(ReactVideoView view, bool paused)
+ {
+ view.IsPaused = paused;
+ }
+
+ [ReactProp("muted")]
+ public void SetMuted(ReactVideoView view, bool muted)
+ {
+ view.IsMuted = muted;
+ }
+
+ [ReactProp("volume", DefaultDouble = 1.0)]
+ public void SetVolume(ReactVideoView view, double volume)
+ {
+ view.Volume = volume;
+ }
+
+ [ReactProp("seek")]
+ public void SetSeek(ReactVideoView view, double? seek)
+ {
+ if (seek.HasValue)
+ {
+ view.Seek(seek.Value);
+ }
+ }
+
+ [ReactProp("rate", DefaultDouble = 1.0)]
+ public void SetPlaybackRate(ReactVideoView view, double rate)
+ {
+ view.Rate = rate;
+ }
+
+ [ReactProp("playInBackground")]
+ public void SetPlayInBackground(ReactVideoView view, bool playInBackground)
+ {
+ throw new NotImplementedException("Play in background has not been implemented on Windows.");
+ }
+
+ [ReactProp("controls")]
+ public void SetControls(ReactVideoView view, bool controls)
+ {
+ view.IsUserControlEnabled = controls;
+ }
+
+ [ReactProp("progressUpdateInterval")]
+ public void SetProgressUpdateInterval(ReactVideoView view, double progressUpdateInterval)
+ {
+ view.ProgressUpdateInterval = progressUpdateInterval;
+ }
+
+ public override void OnDropViewInstance(ThemedReactContext reactContext, ReactVideoView view)
+ {
+ base.OnDropViewInstance(reactContext, view);
+ view.Dispose();
+ }
+
+ protected override ReactVideoView CreateViewInstance(ThemedReactContext reactContext)
+ {
+ return new ReactVideoView
+ {
+ HorizontalAlignment = HorizontalAlignment.Stretch,
+ };
+ }
+ }
+}
diff --git a/windows/ReactNativeVideo/project.json b/windows/ReactNativeVideo/project.json
new file mode 100644
index 00000000..21494af7
--- /dev/null
+++ b/windows/ReactNativeVideo/project.json
@@ -0,0 +1,17 @@
+{
+ "dependencies": {
+ "Microsoft.NETCore.UniversalWindowsPlatform": "5.2.2",
+ "Newtonsoft.Json": "9.0.1"
+ },
+ "frameworks": {
+ "uap10.0": {}
+ },
+ "runtimes": {
+ "win10-arm": {},
+ "win10-arm-aot": {},
+ "win10-x86": {},
+ "win10-x86-aot": {},
+ "win10-x64": {},
+ "win10-x64-aot": {}
+ }
+}
\ No newline at end of file