Skip to content
This repository has been archived by the owner on Mar 30, 2019. It is now read-only.

Commit

Permalink
[MediaFoundation] Fix issue #38. Implemented AsyncCallback for MediaE…
Browse files Browse the repository at this point in the history
…ventGenerator.
  • Loading branch information
Alexandre Mutel committed Jun 25, 2013
1 parent 9d121f8 commit c5e6484
Show file tree
Hide file tree
Showing 7 changed files with 306 additions and 4 deletions.
40 changes: 40 additions & 0 deletions Source/SharpDX.MediaFoundation/AsyncCallbackBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2010-2012 SharpDX - Alexandre Mutel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

namespace SharpDX.MediaFoundation
{
/// <summary>
/// A default implementation of AsyncCallbackBase.
/// </summary>
public abstract class AsyncCallbackBase : CallbackBase, IAsyncCallback
{
public virtual AsyncCallbackFlags Flags
{
get { return AsyncCallbackFlags.None; }
}

public virtual WorkQueueId WorkQueueId
{
get { return WorkQueueId.Standard; }
}

public abstract void Invoke(AsyncResult asyncResult);
}
}
95 changes: 95 additions & 0 deletions Source/SharpDX.MediaFoundation/AsyncCallbackShadow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright (c) 2010-2013 SharpDX - Alexandre Mutel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Runtime.InteropServices;

namespace SharpDX.MediaFoundation
{
/// <summary>
/// Internal AsyncCallback Callback
/// </summary>
internal class AsyncCallbackShadow : SharpDX.ComObjectShadow
{
private static readonly AsyncCallbackVtbl Vtbl = new AsyncCallbackVtbl();

/// <summary>
/// Return a pointer to the unmanaged version of this callback.
/// </summary>
/// <param name="callback">The callback.</param>
/// <returns>A pointer to a shadow c++ callback</returns>
public static IntPtr ToIntPtr(IAsyncCallback callback)
{
return ToCallbackPtr<IAsyncCallback>(callback);
}

public class AsyncCallbackVtbl : ComObjectVtbl
{
public AsyncCallbackVtbl() : base(2)
{
AddMethod(new GetParametersDelegate(GetParametersImpl));
AddMethod(new InvokeDelegate(InvokeImpl));
}

/// <unmanaged>HRESULT IMFAsyncCallback::GetParameters([Out] MFASYNC_CALLBACK_FLAGS* pdwFlags,[Out] unsigned int* pdwQueue)</unmanaged>
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int GetParametersDelegate(IntPtr thisPtr, out AsyncCallbackFlags flags, out WorkQueueId workQueueId);
private static int GetParametersImpl(IntPtr thisPtr, out AsyncCallbackFlags flags, out WorkQueueId workQueueId)
{
flags = AsyncCallbackFlags.None;
workQueueId = WorkQueueId.Standard;
try
{
var shadow = ToShadow<AsyncCallbackShadow>(thisPtr);
var callback = (IAsyncCallback)shadow.Callback;
workQueueId = callback.WorkQueueId;
flags = callback.Flags;
}
catch (Exception exception)
{
return (int)SharpDX.Result.GetResultFromException(exception);
}
return Result.Ok.Code;
}

/// <unmanaged>HRESULT IMFAsyncCallback::Invoke([In, Optional] IMFAsyncResult* pAsyncResult)</unmanaged>
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate int InvokeDelegate(IntPtr thisPtr, IntPtr asyncResult);
private static int InvokeImpl(IntPtr thisPtr, IntPtr asyncResult)
{
try
{
var shadow = ToShadow<AsyncCallbackShadow>(thisPtr);
var callback = (IAsyncCallback)shadow.Callback;
callback.Invoke(new AsyncResult(asyncResult));
}
catch (Exception exception)
{
return (int)SharpDX.Result.GetResultFromException(exception);
}
return Result.Ok.Code;
}
}

protected override CppObjectVtbl GetVtbl
{
get { return Vtbl; }
}
}
}
96 changes: 96 additions & 0 deletions Source/SharpDX.MediaFoundation/AsyncResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) 2010-2013 SharpDX - Alexandre Mutel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

using System;
using System.Runtime.InteropServices;

namespace SharpDX.MediaFoundation
{
public partial class AsyncResult
{
private object state;
private bool isStateVerified;

/// <summary>
/// Gets the state object specified by the caller in the asynchronous <strong>Begin</strong> method. If the value is not <strong><c>null</c></strong>, the caller must dispose.
/// </summary>
/// <value>The state.</value>
/// <remarks>
/// <p>The caller of the asynchronous method specifies the state object, and can use it for any caller-defined purpose. The state object can be <strong><c>null</c></strong>. If the state object is <strong><c>null</c></strong>, <strong>GetState</strong> returns <strong>E_POINTER</strong>.</p><p>If you are implementing an asynchronous method, set the state object on the through the <em>punkState</em> parameter of the <strong><see cref="SharpDX.MediaFoundation.MediaFactory.CreateAsyncResult"/></strong> function.</p><p>This interface is available on the following platforms if the Windows Media Format 11 SDK redistributable components are installed:</p><ul> <li>Windows?XP with Service Pack?2 (SP2) and later.</li> <li>Windows?XP Media Center Edition?2005 with KB900325 (Windows?XP Media Center Edition?2005) and KB925766 (October 2006 Update Rollup for Windows?XP Media Center Edition) installed.</li> </ul>
/// </remarks>
/// <msdn-id>bb970576</msdn-id>
/// <unmanaged>HRESULT IMFAsyncResult::GetState([Out] IUnknown** ppunkState)</unmanaged>
/// <unmanaged-short>IMFAsyncResult::GetState</unmanaged-short>
public object State
{
get
{
if (!isStateVerified)
{
IntPtr statePtr;
GetState(out statePtr);
if (statePtr != IntPtr.Zero)
{
state = Marshal.GetObjectForIUnknown(statePtr);
Marshal.Release(statePtr);
}
isStateVerified = true;
}
return state;
}
}

/// <summary>
/// <p>Get or sets the status of the asynchronous operation.</p>
/// </summary>
/// <value><p>The method returns an <strong><see cref="SharpDX.Result"/></strong>. Possible values include, but are not limited to, those in the following table.</p><table> <tr><th>Return code</th><th>Description</th></tr> <tr><td> <dl> <dt><strong><see cref="SharpDX.Result.Ok"/></strong></dt> </dl> </td><td> <p>The operation completed successfully.</p> </td></tr> </table><p>?</p></value>
/// <remarks>
/// <p>This interface is available on the following platforms if the Windows Media Format 11 SDK redistributable components are installed:</p><ul> <li>Windows?XP with Service Pack?2 (SP2) and later.</li> <li>Windows?XP Media Center Edition?2005 with KB900325 (Windows?XP Media Center Edition?2005) and KB925766 (October 2006 Update Rollup for Windows?XP Media Center Edition) installed.</li> </ul>
/// </remarks>
/// <msdn-id>ms702095</msdn-id>
/// <unmanaged>HRESULT IMFAsyncResult::GetStatus()</unmanaged>
/// <unmanaged-short>IMFAsyncResult::GetStatus</unmanaged-short>
public SharpDX.Result Status
{
get { return GetStatus(); }
set { SetStatus(value); }
}

/// <summary>
/// <p><strong>Applies to: </strong>desktop apps | Metro style apps</p><p> </p><p>Returns an object associated with the asynchronous operation. The type of object, if any, depends on the asynchronous method that was called.</p>
/// </summary>
/// <value><dd> <p>Receives a reference to the object's <strong><see cref="SharpDX.ComObject"/></strong> interface. If no object is associated with the operation, this parameter receives the value <strong><c>null</c></strong>. If the value is not <strong><c>null</c></strong>, the caller must release the interface.</p> </dd></value>
/// <remarks>
/// <p>Typically, this object is used by the component that implements the asynchronous method. It provides a way for the function that invokes the callback to pass information to the asynchronous <strong>End...</strong> method that completes the operation.</p><p>If you are implementing an asynchronous method, you can set the object through the <em>punkObject</em> parameter of the <strong><see cref="SharpDX.MediaFoundation.MediaFactory.CreateAsyncResult"/></strong> function.</p><p>If the asynchronous result object's internal <strong><see cref="SharpDX.ComObject"/></strong> reference is <strong><c>null</c></strong>, the method returns <strong>E_POINTER</strong>.</p><p>This interface is available on the following platforms if the Windows Media Format 11 SDK redistributable components are installed:</p><ul> <li>Windows?XP with Service Pack?2 (SP2) and later.</li> <li>Windows?XP Media Center Edition?2005 with KB900325 (Windows?XP Media Center Edition?2005) and KB925766 (October 2006 Update Rollup for Windows?XP Media Center Edition) installed.</li> </ul>
/// </remarks>
/// <msdn-id>bb970500</msdn-id>
/// <unmanaged>HRESULT IMFAsyncResult::GetObjectW([Out] IUnknown** ppObject)</unmanaged>
/// <unmanaged-short>IMFAsyncResult::GetObjectW</unmanaged-short>
public ComObject PrivateObject
{
get
{
ComObject privateObject;
GetObjectW(out privateObject);
return privateObject;
}
}
}
}
4 changes: 2 additions & 2 deletions Source/SharpDX.MediaFoundation/ByteStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ public unsafe void BeginRead(byte[] bRef, int offset, int count, SharpDX.MediaFo
try
{
fixed (void* ptr = &bRef[offset])
BeginRead__((System.IntPtr) ptr, count, /*TODO callbackRef*/ IntPtr.Zero, GCHandle.ToIntPtr(handle));
BeginRead__((System.IntPtr) ptr, count, AsyncCallbackShadow.ToIntPtr(callbackRef), GCHandle.ToIntPtr(handle));
} finally
{
if (handle.IsAllocated) handle.Free();
Expand Down Expand Up @@ -294,7 +294,7 @@ public unsafe void BeginWrite(byte[] bRef, int offset, int count, SharpDX.MediaF
try
{
fixed (void* ptr = &bRef[offset])
BeginWrite__((System.IntPtr)ptr, count, /* TODO callbackRef */ IntPtr.Zero, GCHandle.ToIntPtr(handle));
BeginWrite__((System.IntPtr)ptr, count, AsyncCallbackShadow.ToIntPtr(callbackRef), GCHandle.ToIntPtr(handle));
}
finally
{
Expand Down
9 changes: 7 additions & 2 deletions Source/SharpDX.MediaFoundation/Mapping-core.xml
Original file line number Diff line number Diff line change
Expand Up @@ -803,8 +803,13 @@
<map param="IMFGetService::GetService::ppvObject" return="true"/>

<map param="IMFAsyncCallback::GetParameters::pdwFlags" type="MFASYNC_CALLBACK_FLAGS"/>



<map method="IMFMediaEventGenerator::GetEvent" name="GetEvent" visibility="internal"/>
<map param="IMFMediaEventGenerator::EndGetEvent::ppEvent" return="true"/>
<map param="IMFMediaEventGenerator::BeginGetEvent::punkState" type="void"/>

<map method="IMFAsyncResult::.*" property="false" visibility="internal"/>
<map param="IMFAsyncResult::GetState::ppunkState" type="void"/>

<!--
// *****************************************************************
Expand Down
62 changes: 62 additions & 0 deletions Source/SharpDX.MediaFoundation/MediaEventGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) 2010-2012 SharpDX - Alexandre Mutel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

using System;
using System.Runtime.InteropServices;

namespace SharpDX.MediaFoundation
{
public partial class MediaEventGenerator
{
/// <summary>
/// <p><strong>Applies to: </strong>desktop apps | Metro style apps</p><p> </p><p>Retrieves the next event in the queue. This method is synchronous.</p>
/// </summary>
/// <param name="isBlocking"><c>true</c> if the method blocks until the event generator queues an event, <c>false</c> otherwise.</param>
/// <returns>a reference to the <strong><see cref="SharpDX.MediaFoundation.MediaEvent"/></strong> interface. The caller must release the interface.</returns>
/// <remarks>
/// <p>This method executes synchronously.</p><p>If the queue already contains an event, the method returns <see cref="SharpDX.Result.Ok"/> immediately. If the queue does not contain an event, the behavior depends on the value of <em>dwFlags</em>:</p><ul> <li> <p>If <em>dwFlags</em> is 0, the method blocks indefinitely until a new event is queued, or until the event generator is shut down.</p> </li> <li> <p>If <em>dwFlags</em> is MF_EVENT_FLAG_NO_WAIT, the method fails immediately with the return code <see cref="SharpDX.MediaFoundation.ResultCode.NoEventsAvailable"/>.</p> </li> </ul><p>This method returns <see cref="SharpDX.MediaFoundation.ResultCode.MultipleSubScribers"/> if you previously called <strong><see cref="SharpDX.MediaFoundation.MediaEventGenerator.BeginGetEvent_"/></strong> and have not yet called <strong><see cref="SharpDX.MediaFoundation.MediaEventGenerator.EndGetEvent"/></strong>.</p>
/// </remarks>
/// <msdn-id>ms704754</msdn-id>
/// <unmanaged>HRESULT IMFMediaEventGenerator::GetEvent([In] unsigned int dwFlags,[Out] IMFMediaEvent** ppEvent)</unmanaged>
/// <unmanaged-short>IMFMediaEventGenerator::GetEvent</unmanaged-short>
public MediaEvent GetEvent(bool isBlocking)
{
MediaEvent mediaEvent;
GetEvent(isBlocking ? 1 : 0, out mediaEvent);
return mediaEvent;
}

/// <summary>
/// <p><strong>Applies to: </strong>desktop apps | Metro style apps</p><p> </p><p>Begins an asynchronous request for the next event in the queue.</p>
/// </summary>
/// <param name="callback"><dd> <p>Pointer to the <strong><see cref="SharpDX.MediaFoundation.IAsyncCallback"/></strong> interface of a callback object. The client must implement this interface.</p> </dd></param>
/// <param name="stateObject">A reference to a state object, defined by the caller. This parameter can be <strong><c>null</c></strong>. You can use this object to hold state information. The object is returned to the caller when the callback is invoked.</param>
/// <remarks>
/// <p>When a new event is available, the event generator calls the <strong><see cref="SharpDX.MediaFoundation.IAsyncCallback.Invoke"/></strong> method. The <strong>Invoke</strong> method should call <strong><see cref="SharpDX.MediaFoundation.MediaEventGenerator.EndGetEvent"/></strong> to get a reference to the <strong><see cref="SharpDX.MediaFoundation.MediaEvent"/></strong> interface, and use that interface to examine the event.</p><p>Do not call <strong>BeginGetEvent</strong> a second time before calling <strong>EndGetEvent</strong>. While the first call is still pending, additional calls to the same object will fail. Also, the <strong><see cref="SharpDX.MediaFoundation.MediaEventGenerator.GetEvent"/></strong> method fails if an asynchronous request is still pending.</p>
/// </remarks>
/// <msdn-id>ms701637</msdn-id>
/// <unmanaged>HRESULT IMFMediaEventGenerator::BeginGetEvent([In] IMFAsyncCallback* pCallback,[In] void* punkState)</unmanaged>
/// <unmanaged-short>IMFMediaEventGenerator::BeginGetEvent</unmanaged-short>
public void BeginGetEvent(IAsyncCallback callback, object stateObject)
{
BeginGetEvent_(AsyncCallbackShadow.ToIntPtr(callback), stateObject == null ? IntPtr.Zero : Marshal.GetIUnknownForObject(stateObject));
}
}
}
Loading

0 comments on commit c5e6484

Please sign in to comment.