using DirectShowLib;
using System;
using System.Runtime.InteropServices;
namespace WPFMediaKit.DirectShow.MediaPlayers;
///
/// The MediaSeekingPlayer adds media seeking functionality to
/// to the MediaPlayerBase class
///
public abstract class MediaSeekingPlayer : MediaPlayerBase
{
///
/// Local cache of the current position
///
private long m_currentPosition;
///
/// The DirectShow media seeking interface
///
private IMediaSeeking m_mediaSeeking;
///
/// Gets the duration in miliseconds, of the media that is opened
///
public virtual long Duration { get; protected set; }
///
/// Sets the rate at which the media plays back
///
public virtual double SpeedRatio
{
get
{
if (m_mediaSeeking == null)
return 1;
double rate;
m_mediaSeeking.GetRate(out rate);
return rate;
}
set
{
if (m_mediaSeeking == null)
return;
double rate = value;
int hr = m_mediaSeeking.SetRate(rate);
}
}
///
/// Gets or sets the position in miliseconds of the media
///
public virtual long MediaPosition
{
get
{
VerifyAccess();
return m_currentPosition;
}
set
{
VerifyAccess();
m_currentPosition = value;
if (m_mediaSeeking != null)
{
/* Try to set the media time */
m_mediaSeeking.SetPositions(m_currentPosition,
AMSeekingSeekingFlags.AbsolutePositioning,
0,
AMSeekingSeekingFlags.NoPositioning);
}
}
}
///
/// The current position format the media is using
///
private MediaPositionFormat m_currentPositionFormat;
///
/// The prefered position format to use with the media
///
private MediaPositionFormat m_preferedPositionFormat;
///
/// The current media positioning format
///
public virtual MediaPositionFormat CurrentPositionFormat
{
get { return m_currentPositionFormat; }
protected set { m_currentPositionFormat = value; }
}
///
/// The prefered media positioning format
///
public virtual MediaPositionFormat PreferedPositionFormat
{
get { return m_preferedPositionFormat; }
set
{
m_preferedPositionFormat = value;
SetMediaSeekingInterface(m_mediaSeeking);
}
}
///
/// Notifies when the position of the media has changed
///
public event EventHandler MediaPositionChanged;
protected void InvokeMediaPositionChanged(EventArgs e)
{
EventHandler mediaPositionChangedHandler = MediaPositionChanged;
if (mediaPositionChangedHandler != null) mediaPositionChangedHandler(this, e);
}
///
/// This method is overriden to get out the seeking
/// interfaces from the DirectShow graph
///
protected override void SetupFilterGraph(IFilterGraph graph)
{
SetMediaSeekingInterface(graph as IMediaSeeking);
base.SetupFilterGraph(graph);
}
///
/// Frees any allocated or unmanaged resources
///
protected override void FreeResources()
{
base.FreeResources();
if (m_mediaSeeking != null)
Marshal.ReleaseComObject(m_mediaSeeking);
m_mediaSeeking = null;
m_currentPosition = 0;
}
///
/// Polls the graph for various data about the media that is playing
///
protected override void OnGraphTimerTick()
{
/* Polls the current position */
if (m_mediaSeeking != null)
{
long lCurrentPos;
int hr = m_mediaSeeking.GetCurrentPosition(out lCurrentPos);
if (hr == 0)
{
if (lCurrentPos != m_currentPosition)
{
m_currentPosition = lCurrentPos;
InvokeMediaPositionChanged(null);
}
}
}
base.OnGraphTimerTick();
}
///
/// Converts a MediaPositionFormat enum to a DShow TimeFormat GUID
///
protected static Guid ConvertPositionFormat(MediaPositionFormat positionFormat)
{
Guid timeFormat;
switch (positionFormat)
{
case MediaPositionFormat.MediaTime:
timeFormat = TimeFormat.MediaTime;
break;
case MediaPositionFormat.Frame:
timeFormat = TimeFormat.Frame;
break;
case MediaPositionFormat.Byte:
timeFormat = TimeFormat.Byte;
break;
case MediaPositionFormat.Field:
timeFormat = TimeFormat.Field;
break;
case MediaPositionFormat.Sample:
timeFormat = TimeFormat.Sample;
break;
default:
timeFormat = TimeFormat.None;
break;
}
return timeFormat;
}
///
/// Converts a DirectShow TimeFormat GUID to a MediaPositionFormat enum
///
protected static MediaPositionFormat ConvertPositionFormat(Guid positionFormat)
{
MediaPositionFormat format;
if (positionFormat == TimeFormat.Byte)
format = MediaPositionFormat.Byte;
else if (positionFormat == TimeFormat.Field)
format = MediaPositionFormat.Field;
else if (positionFormat == TimeFormat.Frame)
format = MediaPositionFormat.Frame;
else if (positionFormat == TimeFormat.MediaTime)
format = MediaPositionFormat.MediaTime;
else if (positionFormat == TimeFormat.Sample)
format = MediaPositionFormat.Sample;
else
format = MediaPositionFormat.None;
return format;
}
protected void SetDuration()
{
if (m_mediaSeeking == null)
return;
long duration;
/* Get the duration of the media. This value will
* be in whatever format that was set. ie Frame, MediaTime */
m_mediaSeeking.GetDuration(out duration);
Duration = duration;
}
///
/// Setup the IMediaSeeking interface
///
protected void SetMediaSeekingInterface(IMediaSeeking mediaSeeking)
{
m_mediaSeeking = mediaSeeking;
if (mediaSeeking == null)
{
CurrentPositionFormat = MediaPositionFormat.None;
Duration = 0;
return;
}
/* Get our prefered DirectShow TimeFormat */
Guid preferedFormat = ConvertPositionFormat(PreferedPositionFormat);
/* Attempt to set the time format */
mediaSeeking.SetTimeFormat(preferedFormat);
Guid currentFormat;
/* Gets the current time format
* we may not have been successful
* setting our prefered format */
mediaSeeking.GetTimeFormat(out currentFormat);
/* Set our property up with the right format */
CurrentPositionFormat = ConvertPositionFormat(currentFormat);
SetDuration();
}
}