The SourceFrameGet method returns only the next source frame. It is useful for live sources or for a simple file playback. For more complicated operations like seeking or fast playback, you should use other methods of IMFSource interface.
Seeking
Each frame within a file has its number and its position. You can use these parameters to get a frame with SourceFrameGetByNumber and SourceFrameGetByTime methods.
The SourceFrameGetByNumber method contains these parameters:
- _nFrameNo - frame number to seek to
- _rtMaxWait - maximal wait time for a frame in 100-nanoseconds units
- _ppFrame - a source frame from the target position.
- _bsHints - additional parameters. This parameter is used in playback control and described below.
To seek to, for example, 57th frame in the file you should call:
MFFrame mySeekingFrame;
((IMFSource)myReader).SourceFrameGetByNumber(57, -1, out mySeekingFrame, "");
The SourceFrameGetByTime method uses the same parameters except for the 1st one. For this method, it is _dblTimeSec - a position of the target frame in seconds.
To seek to 15th second of the file you should call
MFFrame mySeekingFrame;
((IMFSource)myReader).SourceFrameGetByTime(15.0, -1, out mySeekingFrame, "");
In both cases, the file position is specified and further playback continues from that position.
Seeking by timecode
There is a property for MFReader object with which you can seek by timecode - "tc_pos". The property is set-only, so once it is set, the next call for SourceFrameGetByNumber(-1, -1, out mySeekingFrame, "") returns you a frame with the specified timecode. After that, the value of "tc_pos" is not available - if you call for PropsGet("tc_pos", out myValue) - it returns you null or empty string.
For example:
(myReader as IMProps).PropsSet("tc_pos", "01:23:45:12");
myReader.SourceFrameGetByNumber(-1, -1, out mySeekingFrame, "");
Fast playback
For both SourceFrameGetByNumber and SourceFrameGetByTime methods it is possible to use negative values for target number and time. If you use '-1' as value the source object returns you the next frame. So for simple playback you can change the main thread body to this variant with SourceFrameGetByTime method:
// a frame object
MFFrame myFrame;
// grab a frame
((IMFSource)myReader).SourceFrameGetByTime(-1, -1, out myFrame, "");
// or with
// ((IMFSource)myReader).SourceFrameGetByNumber(-1, -1, out myFrame, "");
// send to receiver
((IMFReceiver)myPreview).ReceiverFramePut(myFrame, -1, "");
or to this one with SourceFrameGetByNumber method:
// a frame object
MFFrame myFrame;
// grab a frame
((IMFSource)myReader).SourceFrameGetByTime(-1, -1, out myFrame, "");
// or with
// ((IMFSource)myReader).SourceFrameGetByNumber(-1, -1, out myFrame, "");
// send to receiver
((IMFReceiver)myPreview).ReceiverFramePut(myFrame, -1, "");
Fast playback means that instead of each frame playback some frames are skipped. For example, x2 speed means that you see each 2nd frame on preview. To make x2 playback with these methods you should set '-2' as target position for these methods:
((IMFSource)myReader).SourceFrameGetByTime(-2, -1, out myFrame, "");
or
((IMFSource)myReader).SourceFrameGetByNumber(-2, -1, out myFrame, "");
The same is for any speed: x5 playback means to use '-5' as a parameter.
It is possible to use only integer values as negative for these methods so to make slow playback you should send the same frame to receiver several times.
x0.5 playback means that you see the same frame twice a long as it usually gets. To make this effect in the source-receiver thread you should do something like this:
// a frame object
MFFrame myFrame;
// grab a frame
((IMFSource)myReader).SourceFrameGetByTime(-1, -1, out myFrame, "");
for (int slowIterator = 0; slowIterator<slowRate; slowIterator++)
{
((IMFReceiver)myPreview).ReceiverFramePut(myFrame, -1, "");
}
where slowRate may be '2' for x0.5 speed playback, '4 for x0.25 playback etc.
Fast and slow playback in the Expert edition of MFormats SDK:
There is a "rate" property in _bsHints parameter to specify a variable rate for playback. You can specify any value for rate, e.g. "rate=0.5" for slow playback or "rate=2.5" for fast playback. For example:
((IMFSource)myReader).SourceFrameGetByTime(-1, -1, out myFrame, "rate=0.5");
Note, that negative values are ignored because reverse playback is managed by another property.
Start and Stop
Play and Stop playback operations are managed by the core thread itself. To stop a playback you should stop the thread or just don't call core methods. To resumes a playback you should resume the thread.
Pause
All the IMFSource interface methods contain _bsHints parameter. Using 'pause=true' in this parameter makes a source pause on the current frame and returns you the same frame all the time while the parameter is specified. To pause playback you should do the following:
((IMFSource)myReader).SourceFrameGetByNumber(-1, -1, out myFrame, "pause=true");
Until you call
((IMFSource)myReader).SourceFrameGetByNumber(-1, -1, out myFrame, "");
the MFReader object will return you the same frame. As soon you make _bsHints parameter empty the playback resumes.
Frame by frame playback
To make frame-by-frame playback you should get a frame from source and once the frame is received, set "pause=true" for the _bsHints parameter.
Reverse playback
To reverse the playback you should set _bsHints to 'reverse=true'. In this case, the behavior of IMFSource interface methods will be changed:
- SourceFrameGet will return you the previous frame
- SourceFrameGetByNumber and SourceFrameGetByTime will work as in common case if the target position is positive (e.g. 57th frame or 15th second), but will return you previous frames in case of the negative target position, e.g. '-1'.
So simple reverse playback looks like:
// a frame object
MFFrame myFrame;
// grab a frame
((IMFSource)myReader).SourceFrameGetByTime(-1, -1, out myFrame, "reverse=true");
// or with
// ((IMFSource)myReader).SourceFrameGetByNumber(-1, -1, out myFrame, "reverse=true");
// send to receiver
((IMFReceiver)myPreview).ReceiverFramePut(myFrame, -1, "");
_bsHints usage
You can combine several properties in a single string to control the playback. For example, to make a slow reverse playback, you could use _bsHints="reverse=true rate=0.5".