CSourceSeeking Class
Microsoft DirectShow 9.0 |
CSourceSeeking Class
The CSourceSeeking class is an abstract class for implementing seeking in source filters with one output pin.
This class supports the IMediaSeeking interface. It provides default implementations for all of the IMediaSeeking methods. Protected member variables store the start time, stop time, and current rate. By default, the only time format supported by the class is TIME_FORMAT_MEDIA_TIME (100-nanosecond units). See Remarks for more information.
Requirements
** Header:** Declared in Ctlutil.h; include Streams.h.
** Library:** Use Strmbase.lib (retail builds) or Strmbasd.lib (debug builds).
Protected Member Variables | |
m_rtDuration | Duration of the stream. |
m_rtStart | Start time. |
m_rtStop | Stop time. |
m_dRateSeeking | Playback rate. |
m_dwSeekingCaps | Seeking capabilities. |
m_pLock | Pointer to a critical section object for locking. |
Protected Methods | |
CSourceSeeking | Constructor method. |
Pure Virtual Methods | |
ChangeRate | Called when the playback rate changes. |
ChangeStart | Called when the start position changes. |
ChangeStop | Called when the stop position changes. |
IMediaSeeking Methods | |
IsFormatSupported | Determines whether a specified time format is supported. |
QueryPreferredFormat | Retrieves the object's preferred time format. |
SetTimeFormat | Sets the time format. |
IsUsingTimeFormat | Determines whether a specified time format is the format currently in use. |
GetTimeFormat | Retrieves the current time format. |
GetDuration | Retrieves the duration of the stream. |
GetStopPosition | Retrieves the time at which the playback will stop, relative to the duration of the stream. |
GetCurrentPosition | Retrieves the current position, relative to the total duration of the stream. |
GetCapabilities | Retrieves all the seeking capabilities of the stream. |
CheckCapabilities | Queries whether the stream has specified seeking capabilities. |
ConvertTimeFormat | Converts from one time format to another. |
SetPositions | Sets the current position and the stop position. |
GetPositions | Retrieves the current position and the stop position. |
GetAvailable | Retrieves the range of times in which seeking is efficient. |
SetRate | Sets the playback rate. |
GetRate | Retrieves the playback rate. |
GetPreroll | Retrieves the preroll time. |
Remarks
Whenever the start position, stop position, or playback rate changes, the CSourceSeeking object calls a corresponding pure virtual method:
- Start position: CSourceSeeking::ChangeStart
- Stop position: CSourceSeeking::ChangeStop
- Playback rate: CSourceSeeking::ChangeRate
The derived class must implement these methods. After any seek operation, a filter must do the following:
- Call the IPin::BeginFlush method on the downstream input pin.
- Halt the worker thread that is delivering data.
- Call the IPin::EndFlush method on the input pin.
- Restart the worker thread.
- Call the IPin::NewSegment method on the input pin.
- Set the discontinuity property on the first sample. Call the IMediaSample::SetDiscontinuity method.
The call to BeginFlush frees the worker thread, if the thread is blocked waiting to deliver a sample.
In step 2, make sure that the thread has stopped sending data. Depending on the implementation, you might need to wait for the thread to exit, or for the thread to signal a response of some kind. If your filter uses the CSourceStream class, the CSourceStream::Stop method blocks until the worker thread replies.
Ideally, the new segment (step 5) should be delivered from the worker thread. It can also be done by the CSourceSeeking object, as long as the filter serializes it with the samples.
The following example shows a possible implementation. It assumes that the source filter's output pin is derived from CSourceSeeking and CSourceStream. This example defines a helper method, UpdateFromSeek, that performs steps 1–4. The CSourceStream::OnThreadStartPlay method is overridden to send the new segment, and to set a flag indicating the discontinuity. The worker thread picks up this flag and calls the IMediaSample::SetDiscontinuity method:
void CMyStream::UpdateFromSeek() { if (ThreadExists()) { DeliverBeginFlush(); Stop(); DeliverEndFlush(); Run(); } } HRESULT CMyStream::OnThreadStartPlay() { m_bDiscontinuity = TRUE; return DeliverNewSegment(m_rtStart, m_rtStop, m_dRateSeeking); }
Supporting Additional Time Formats
By default, this class supports seeking only in units of reference time (TIME_FORMAT_MEDIA_TIME). To support additional time formats, override the IMediaSeeking methods that deal with time formats:
- IMediaSeeking::GetTimeFormat
- IMediaSeeking::IsFormatSupported
- IMediaSeeking::IsUsingTimeFormat
- IMediaSeeking::QueryPreferredFormat
- IMediaSeeking::SetTimeFormat
In addition, override the remaining IMediaSeeking methods to perform the necessary conversions between time formats. After the SetTimeFormat method is called, all IMediaSeeking methods must treat incoming and outgoing time parameters as being in the new time format. For example, if the m_rtDuration variable represents the duration in units of reference time, but the current time format is frames, then the GetDuration method must return the value m_rtDuration converted to frames. For example:
STDMETHODIMP GetDuration(LONGLONG *pDuration) { HRESULT hr = CSourceSeeking::GetDuration(pDuration); if (SUCCEEDED(hr)) { if (m_TimeFormat == TIME_FORMAT_FRAME) { // Convert from reference time to frames. *pDuration = TimeToFrame(*pDuration); // Private method. } } return hr }
Also, make sure to check for the AM_SEEKING_ReturnTime flag in the IMediaSeeking::SetPositions method. If this flag is present, convert the position values into reference times when you return them to the caller.