I am attempting to record an animation (computer graphics, not video) to a WMV file using DirectShow. The setup is:
-
A Push Source that uses an in-memory bitmap holding the animation frame. Each time FillBuffer() is called, the bitmap’s data is copied over into the sample, and the sample is timestamped with a start time (frame number * frame length) and duration (frame length). The frame rate is set to 10 frames per second in the filter.
-
An ASF Writer filter. I have a custom profile file that sets the video to 10 frames per second. Its a video-only filter, so there’s no audio.
The pins connect, and when the graph is run, a wmv file is created. But…
The problem is it appears DirectShow is pushing data from the Push Source at a rate greater than 10 FPS. So the resultant wmv, while playable and containing the correct animation (as well as reporting the correct FPS), plays the animation back several times too slowly because too many frames were added to the video during recording. That is, a 10 second video at 10 FPS should only have 100 frames, but about 500 are being stuffed into the video, resulting in the video being 50 seconds long.
My initial attempt at a solution was just to slow down the FillBuffer() call by adding a sleep() for 1/10th second. And that indeed does more or less work. But it seems hackish, and I question whether that would work well at higher FPS.
So I’m wondering if there’s a better way to do this. Actually, I’m assuming there’s a better way and I’m just missing it. Or do I just need to smarten up the manner in which FillBuffer() in the Push Source is delayed and use a better timing mechanism?
Any suggestions would be greatly appreciated!
I am doing just the right thing for my recorder application (www.videophill.com) for purposes of testing the whole thing.
I am using
Sleep()method to delay the frames, but am taking great care to ensure that timestamps of the frames are correct. Also, whenSleep()ing from frame to frame, please try to use ‘absolute’ time differences, becauseSleep(100)will sleep about 100ms, not exactly 100ms.If it won’t work for you, you can always go for IReferenceClock, but I think that’s overkill here.
So:
EDIT:
Keep in mind:
IWMWritteris time insensitive as long as you feed it with SAMPLES that are properly time-stamped.