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(); } }