From 8dc3dfe23bdd4e98070c990ff776ae7171c4412e Mon Sep 17 00:00:00 2001 From: Ray Batts Date: Wed, 2 Apr 2014 18:18:47 -0500 Subject: [PATCH 1/7] Video support for Windows 8 Store apps. --- Build/Projects/MonoGame.Framework.definition | 9 +- .../Content/ContentReaders/VideoReader.cs | 65 +++------ .../Content/ContentTypeReaderManager.cs | 8 +- .../Graphics/GraphicsDevice.DirectX.cs | 4 + MonoGame.Framework/Graphics/Texture2D.cs | 2 +- MonoGame.Framework/Media/Video.cs | 36 ++--- MonoGame.Framework/Media/VideoPlayer.WME.cs | 134 ++++++++++++++++++ MonoGame.Framework/Media/VideoPlayer.cs | 28 +++- 8 files changed, 204 insertions(+), 82 deletions(-) create mode 100644 MonoGame.Framework/Media/VideoPlayer.WME.cs diff --git a/Build/Projects/MonoGame.Framework.definition b/Build/Projects/MonoGame.Framework.definition index b153eb5c43c..f79ff96d42f 100644 --- a/Build/Projects/MonoGame.Framework.definition +++ b/Build/Projects/MonoGame.Framework.definition @@ -249,7 +249,7 @@ Android,iOS,Linux,MacOS,Ouya,Windows8,Windows,WindowsGL,WindowsPhone - Linux,PSMobile,Windows,Windows8,WindowsGL,WindowsPhone + Linux,PSMobile,Windows,WindowsGL,WindowsPhone @@ -731,7 +731,7 @@ - Linux,PSMobile,Windows,Windows8,WindowsGL,WindowsPhone + Linux,PSMobile,Windows,WindowsGL,WindowsPhone iOS @@ -743,11 +743,14 @@ Android,Ouya - Linux,PSMobile,Windows,Windows8,WindowsGL,WindowsPhone + Linux,PSMobile,Windows,WindowsGL,WindowsPhone iOS + + Windows8 + MacOS diff --git a/MonoGame.Framework/Content/ContentReaders/VideoReader.cs b/MonoGame.Framework/Content/ContentReaders/VideoReader.cs index 2d0280436e6..540b08f5da4 100644 --- a/MonoGame.Framework/Content/ContentReaders/VideoReader.cs +++ b/MonoGame.Framework/Content/ContentReaders/VideoReader.cs @@ -1,47 +1,9 @@ -// #region License -// /* -// Microsoft Public License (Ms-PL) -// MonoGame - Copyright © 2009 The MonoGame Team -// -// All rights reserved. -// -// This license governs use of the accompanying software. If you use the software, you accept this license. If you do not -// accept the license, do not use the software. -// -// 1. Definitions -// The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under -// U.S. copyright law. -// -// A "contribution" is the original software, or any additions or changes to the software. -// A "contributor" is any person that distributes its contribution under this license. -// "Licensed patents" are a contributor's patent claims that read directly on its contribution. -// -// 2. Grant of Rights -// (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, -// each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. -// (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, -// each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. -// -// 3. Conditions and Limitations -// (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. -// (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, -// your patent license from such contributor to the software ends automatically. -// (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution -// notices that are present in the software. -// (D) If you distribute any portion of the software in source code form, you may do so only under this license by including -// a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object -// code form, you may only do so under a license that complies with this license. -// (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees -// or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent -// permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular -// purpose and non-infringement. -// */ -// #endregion License -// +// MonoGame - Copyright (C) The MonoGame Team +// This file is subject to the terms and conditions defined in +// file 'LICENSE.txt', which is part of this source code package. using System; using System.IO; - using Microsoft.Xna.Framework.Media; namespace Microsoft.Xna.Framework.Content @@ -52,6 +14,8 @@ internal class VideoReader : ContentTypeReader - Linux,PSMobile,Windows,WindowsGL,WindowsPhone + Linux,PSMobile,WindowsGL,WindowsPhone @@ -730,7 +730,7 @@ - Linux,PSMobile,Windows,WindowsGL,WindowsPhone + Linux,PSMobile,WindowsGL,WindowsPhone iOS @@ -741,8 +741,11 @@ Android,Ouya + + Windows + - Linux,PSMobile,Windows,WindowsGL,WindowsPhone + Linux,PSMobile,WindowsGL,WindowsPhone iOS @@ -756,6 +759,9 @@ Android,Ouya + + Windows + @@ -1212,6 +1218,9 @@ Windows + + Windows + diff --git a/MonoGame.Framework/Media/Video.WMS.cs b/MonoGame.Framework/Media/Video.WMS.cs new file mode 100644 index 00000000000..581e3dc4be8 --- /dev/null +++ b/MonoGame.Framework/Media/Video.WMS.cs @@ -0,0 +1,119 @@ +using SharpDX; +using SharpDX.MediaFoundation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Microsoft.Xna.Framework.Media +{ + public sealed partial class Video : IDisposable + { + private Topology _topology; + internal Topology Topology { get { return _topology; } } + + internal VideoSampleGrabber SampleGrabber { get; private set; } + + MediaType _mediaType; + + private void PlatformInitialize() + { + if (Topology != null) + return; + + MediaManagerState.CheckStartup(); + + MediaFactory.CreateTopology(out _topology); + + SharpDX.MediaFoundation.MediaSource mediaSource; + { + SourceResolver resolver; + MediaFactory.CreateSourceResolver(out resolver); + + ObjectType otype; + ComObject source; + resolver.CreateObjectFromURL(FileName, (int)SourceResolverFlags.MediaSource, null, out otype, + out source); + mediaSource = source.QueryInterface(); + resolver.Dispose(); + source.Dispose(); + } + + PresentationDescriptor presDesc; + mediaSource.CreatePresentationDescriptor(out presDesc); + + for (var i = 0; i < presDesc.StreamDescriptorCount; i++) + { + Bool selected; + StreamDescriptor desc; + presDesc.GetStreamDescriptorByIndex(i, out selected, out desc); + + if (selected) + { + TopologyNode sourceNode; + MediaFactory.CreateTopologyNode(TopologyType.SourceStreamNode, out sourceNode); + + sourceNode.Set(TopologyNodeAttributeKeys.Source, mediaSource); + sourceNode.Set(TopologyNodeAttributeKeys.PresentationDescriptor, presDesc); + sourceNode.Set(TopologyNodeAttributeKeys.StreamDescriptor, desc); + + TopologyNode outputNode; + MediaFactory.CreateTopologyNode(TopologyType.OutputNode, out outputNode); + + var majorType = desc.MediaTypeHandler.MajorType; + if (majorType == MediaTypeGuids.Video) + { + Activate activate; + + SampleGrabber = new VideoSampleGrabber(); + + _mediaType = new MediaType(); + + _mediaType.Set(MediaTypeAttributeKeys.MajorType, MediaTypeGuids.Video); + + // Specify that we want the data to come in as RGB32. + _mediaType.Set(MediaTypeAttributeKeys.Subtype, new Guid("00000016-0000-0010-8000-00AA00389B71")); + + MediaFactory.CreateSampleGrabberSinkActivate(_mediaType, SampleGrabber, out activate); + outputNode.Object = activate; + } + + if (majorType == MediaTypeGuids.Audio) + { + Activate activate; + MediaFactory.CreateAudioRendererActivate(out activate); + + outputNode.Object = activate; + } + + _topology.AddNode(sourceNode); + _topology.AddNode(outputNode); + sourceNode.ConnectOutput(0, outputNode, 0); + + sourceNode.Dispose(); + outputNode.Dispose(); + } + + desc.Dispose(); + } + + presDesc.Dispose(); + mediaSource.Dispose(); + } + + private void PlatformDispose(bool disposing) + { + if (_topology != null) + { + _topology.Dispose(); + _topology = null; + } + + if (SampleGrabber != null) + { + SampleGrabber.Dispose(); + SampleGrabber = null; + } + } + } +} diff --git a/MonoGame.Framework/Media/Video.cs b/MonoGame.Framework/Media/Video.cs index 0044db4ad22..5ac20e6248d 100644 --- a/MonoGame.Framework/Media/Video.cs +++ b/MonoGame.Framework/Media/Video.cs @@ -60,7 +60,7 @@ internal Video(string fileName) { FileName = fileName; -#if !WINDOWS && !WINRT +#if !WINRT PlatformInitialize(); #endif } diff --git a/MonoGame.Framework/Media/VideoPlayer.WMS.cs b/MonoGame.Framework/Media/VideoPlayer.WMS.cs new file mode 100644 index 00000000000..f5bb38e9232 --- /dev/null +++ b/MonoGame.Framework/Media/VideoPlayer.WMS.cs @@ -0,0 +1,142 @@ +using Microsoft.Xna.Framework.Graphics; +using SharpDX; +using SharpDX.MediaFoundation; +using SharpDX.Win32; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Microsoft.Xna.Framework.Media +{ + public sealed partial class VideoPlayer : IDisposable + { + private static MediaSession _session; + private static SimpleAudioVolume _volumeController; + private static PresentationClock _clock; + + // HACK: Need SharpDX to fix this. + private static readonly Guid MRPolicyVolumeService = Guid.Parse("1abaa2ac-9d3b-47c6-ab48-c59506de784d"); + private static readonly Guid SimpleAudioVolumeGuid = Guid.Parse("089EDF13-CF71-4338-8D13-9E569DBDC319"); + + private static Callback _callback; + + private class Callback : IAsyncCallback + { + public void Dispose() + { + } + + public IDisposable Shadow { get; set; } + public void Invoke(AsyncResult asyncResultRef) + { + var ev = _session.EndGetEvent(asyncResultRef); + + // Trigger an "on Video Ended" event here if needed + + _session.BeginGetEvent(this, null); + } + + public AsyncCallbackFlags Flags { get; private set; } + public WorkQueueId WorkQueueId { get; private set; } + } + + private void PlatformInitialize() + { + MediaManagerState.CheckStartup(); + MediaFactory.CreateMediaSession(null, out _session); + } + + private Texture2D PlatformGetTexture() + { + var sampleGrabber = _currentVideo.SampleGrabber; + + var texData = sampleGrabber.TextureData; + + if (texData == null) + return null; + + // TODO: This could likely be optimized if we held on to the SharpDX Surface/Texture data, + // and set it on an XNA one rather than constructing a new one every time this is called. + var retTex = new Texture2D(Game.Instance.GraphicsDevice, _currentVideo.Width, _currentVideo.Height, false, SurfaceFormat.Bgr32); + + retTex.SetData(texData); + + return retTex; + } + + private void PlatformPause() + { + _session.Pause(); + } + + private void PlatformPlay() + { + // Cleanup the last song first. + if (State != MediaState.Stopped) + { + _session.Stop(); + _volumeController.Dispose(); + _clock.Dispose(); + } + + // Set the new song. + _session.SetTopology(0, _currentVideo.Topology); + + // Get the volume interface. + IntPtr volumeObj; + + + try + { + MediaFactory.GetService(_session, MRPolicyVolumeService, SimpleAudioVolumeGuid, out volumeObj); + } + catch + { + MediaFactory.GetService(_session, MRPolicyVolumeService, SimpleAudioVolumeGuid, out volumeObj); + } + + + _volumeController = CppObject.FromPointer(volumeObj); + _volumeController.Mute = IsMuted; + _volumeController.MasterVolume = _volume; + + // Get the clock. + _clock = _session.Clock.QueryInterface(); + + //create the callback if it hasn't been created yet + if (_callback == null) + { + _callback = new Callback(); + _session.BeginGetEvent(_callback, null); + } + + // Start playing. + var varStart = new Variant(); + _session.Start(null, varStart); + } + + private void PlatformResume() + { + _session.Start(null, null); + } + + private void PlatformStop() + { + _session.Stop(); + } + + private void PlatformSetVolume() + { + if (_volumeController == null) + return; + + _volumeController.MasterVolume = _volume; + } + + private TimeSpan PlatformGetPlayPosition() + { + return TimeSpan.Zero; + } + } +} diff --git a/MonoGame.Framework/Media/VideoSampleGrabber.cs b/MonoGame.Framework/Media/VideoSampleGrabber.cs new file mode 100644 index 00000000000..14792670698 --- /dev/null +++ b/MonoGame.Framework/Media/VideoSampleGrabber.cs @@ -0,0 +1,57 @@ +using SharpDX.MediaFoundation; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; + +namespace Microsoft.Xna.Framework.Media +{ + internal class VideoSampleGrabber : SharpDX.CallbackBase, SampleGrabberSinkCallback + { + internal byte[] TextureData { get; private set; } + + public void OnProcessSample(Guid guidMajorMediaType, int dwSampleFlags, long llSampleTime, long llSampleDuration, IntPtr sampleBufferRef, int dwSampleSize) + { + if (TextureData == null || TextureData.Length != dwSampleSize) + TextureData = new byte[dwSampleSize]; + + Marshal.Copy(sampleBufferRef, TextureData, 0, dwSampleSize); + } + + public void OnSetPresentationClock(PresentationClock presentationClockRef) + { + + } + + public void OnShutdown() + { + + } + + public void OnClockPause(long systemTime) + { + + } + + public void OnClockRestart(long systemTime) + { + + } + + public void OnClockSetRate(long systemTime, float flRate) + { + + } + + public void OnClockStart(long systemTime, long llClockStartOffset) + { + + } + + public void OnClockStop(long hnsSystemTime) + { + + } + } +} From 3c7ac6e5a74f2021e0e4e013dff986546349c85d Mon Sep 17 00:00:00 2001 From: Ray Batts Date: Tue, 22 Apr 2014 18:47:07 -0500 Subject: [PATCH 4/7] Submodule update. --- ThirdParty/Dependencies | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ThirdParty/Dependencies b/ThirdParty/Dependencies index 420b75d6d5b..c4950b60b2c 160000 --- a/ThirdParty/Dependencies +++ b/ThirdParty/Dependencies @@ -1 +1 @@ -Subproject commit 420b75d6d5b2c966bfc85a46b4de860a3ae7ab38 +Subproject commit c4950b60b2c4ad153d456cc1de75c459b1347cee From f8c86dd243875e62dc607c6a9adc2b034dc2da44 Mon Sep 17 00:00:00 2001 From: Ray Batts Date: Tue, 22 Apr 2014 19:19:08 -0500 Subject: [PATCH 5/7] #ifdef-ed around the dummy ContentReader initializations done to prevent linker stripping on iOS devices. --- MonoGame.Framework/Content/ContentTypeReaderManager.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MonoGame.Framework/Content/ContentTypeReaderManager.cs b/MonoGame.Framework/Content/ContentTypeReaderManager.cs index 4670a22e911..a475db3f463 100644 --- a/MonoGame.Framework/Content/ContentTypeReaderManager.cs +++ b/MonoGame.Framework/Content/ContentTypeReaderManager.cs @@ -112,7 +112,12 @@ internal ContentTypeReader[] LoadAssetReaders() var hExternalReferenceReader = new ExternalReferenceReader(); var hSoundEffectReader = new SoundEffectReader(); var hSongReader = new SongReader(); + + // At the moment the Video class doesn't exist + // on all platforms... Allow it to compile anyway. +#if ANDROID || IOS || MONOMAC || (WINDOWS && !OPENGL) || WINRT var hVideoReader = new VideoReader(); +#endif } #pragma warning restore 0219, 0649 From a6317be9324c8c0b04e274a8a224f7271727c4fd Mon Sep 17 00:00:00 2001 From: Ray Batts Date: Tue, 22 Apr 2014 19:33:18 -0500 Subject: [PATCH 6/7] Excluding Windows Phone from dummy VideoReader initialization. --- MonoGame.Framework/Content/ContentTypeReaderManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MonoGame.Framework/Content/ContentTypeReaderManager.cs b/MonoGame.Framework/Content/ContentTypeReaderManager.cs index a475db3f463..a41532d8520 100644 --- a/MonoGame.Framework/Content/ContentTypeReaderManager.cs +++ b/MonoGame.Framework/Content/ContentTypeReaderManager.cs @@ -115,7 +115,7 @@ internal ContentTypeReader[] LoadAssetReaders() // At the moment the Video class doesn't exist // on all platforms... Allow it to compile anyway. -#if ANDROID || IOS || MONOMAC || (WINDOWS && !OPENGL) || WINRT +#if ANDROID || IOS || MONOMAC || (WINDOWS && !OPENGL) || (WINRT && !WINDOWS_PHONE) var hVideoReader = new VideoReader(); #endif } From 19a951783066432f78c57eec09d3cc07142919a0 Mon Sep 17 00:00:00 2001 From: Ray Batts Date: Tue, 22 Apr 2014 19:42:34 -0500 Subject: [PATCH 7/7] Excluding VideoReader from the web platform. --- Build/Projects/MonoGame.Framework.definition | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Build/Projects/MonoGame.Framework.definition b/Build/Projects/MonoGame.Framework.definition index ad28690ba27..9e07c24666f 100644 --- a/Build/Projects/MonoGame.Framework.definition +++ b/Build/Projects/MonoGame.Framework.definition @@ -268,7 +268,7 @@ Android,iOS,Linux,MacOS,Ouya,Windows8,Windows,WindowsGL,WindowsPhone - Linux,PSMobile,WindowsGL,WindowsPhone + Linux,PSMobile,WindowsGL,WindowsPhone,Web