I have a DirectShow application where I maintain a clock externally, and I need to sync video to this clock. The external clock may not be wall clock time; it might be going faster, it might be going slower, all my application knows is that it's being fed timestamps in strictly increasing order and must sync video playback to that timestamp each frame.
My graph is currently set up with some input filter eventually leading to an ISampleGrabber. I've been able to achieve what I want, for the most part, using IMediaPosition:: put_CurrentPostion before getting each frame via ISampleGrabber::GetCurrentBuffer -- although it's not perfect. What is the best way to do this?
There are a couple of reasons why my current method isn't any good:
1) Not all codecs seem to support seeking this way.
2) DirectShow seems to create a background thread that's always decoding, and everything happens asynchronously, and so it's not necessarily true that the GetCurrentBuffer() call actually does get me the frame at the precise timestamp I asked for (and I do get a lot of unacceptable "time jitter" and other issues when I try to play the video back very slowly using this method).
3) DirectShow's background thread is always decoding stuff -- and usually that means it's working on decoding frames that I don't care about, since I'm going to use put_CurrentPosition every time anyway. I'd like to not waste CPU here, and just have it decode frames on-demand.
I don't need to worry about playing videos backwards, which may simplify things.
Any advice is welcome,
Thanks,
J
+ Reply to Thread
Results 1 to 5 of 5
-
-
You could create a custom filter that only passes samples downstream when you want them to be decoded. i.e., when the filter's input pin's Receive() method is called, either ignore it or call the output pin'd Deliver() method.
I use this with a filter that accepts four inputs continuously but only one should be output.John Miller -
Thanks for your reply. I actually got a solution working today. If you query IMediaFilter from the graph builder, it exposes a method SetSyncSource. You can provide it with any IReferenceClock and it will use that as the timing source instead of it's own internal clock. It's really nice and transparent, too, you don't have to modify any code, just set the sync source and bam, everything works like magic.
Of course, actually writing it was a hassle. The samples do provide a CRefClock (which in theory is incredible easy to use, override CRefClock::GetPrivateTime() and pass an instance of your reference clock to IMediaFilter::SetSyncSource), but I was having some stability issues with it and also, of course, it didn't mix well with GCC or Borland's compiler, both which are important to me. About a full day's worth of work eventually yielded me with my own IReferenceClock clock source (although it won't take that long the second time around). I'd post the source here but it doesn't compile outside the context of my application, but if somebody asks I will try to make it standalone. Maybe I'll stick it on CodeProject or something some day (it's directshow base class and ATL-free).
I did run into an issue where it seems that the filter graph builder does something like this on your reference clock when you Release() the graph builder:
while (refclock->Release())
;
Which turned into a major pain. I don't know why it doesn't match it's addrefs and releases. Maybe to work around some internal buggy filters not Releasing the reference clock.
Even this solution isn't perfect but I think it's as close as I can get. Using the reference clock, the decoder will never drop frames. So if your clock advances time more quickly than the decoder can decode, then weird things start to happen (the same weird things that happen when you set the playback rate too high with IMediaPosition). I'm not sure how to enable frame dropping (do you know?).
I read your reply to my other thread, "where to get DirectShow help". The samples and documentation are great, of course, but sometimes DirectShow does some really weird stuff that just isn't documented, and it'd be nice to have somebody with some experience to guide me down the right path (for example, you won't find -anywhere- in the documentation or examples something that says the graph builder loops Release()ing your reference clock until it's free'd -- hell, the docs say the return value of Release() is for diagnostic purposes -period-, yet DirectShow's own internal implementation relies on its result).
Maybe I'll come to videohelp from now on. I got no responses to this question on the official MS DirectShow forum as well as both newsgroups. It's kind of depressing.
J -
Does this snippet of information help you in any way:
>>
If you need to select a specific filter as the reference clock, the simplest way to do this is to make a filter graph containing only the filter you want as clock, then call Run and Stop on this before making the rest of the graph.
This works because the graph manager selects a clock when the graph goes active, but only if a clock has not already been selected.
<< -
Thanks for your reply! I was able to set the clock with no problems with IMediaFilter::SetSyncSource, but that's an interesting tip. I'll have to file that one away.
- J
Similar Threads
-
How to control font size and position in Subtitle Workshop
By pchan in forum SubtitleReplies: 2Last Post: 19th Jan 2010, 07:08 -
Cropping and moving video position in VEGAS 7
By Rudyard in forum Newbie / General discussionsReplies: 7Last Post: 26th Nov 2008, 17:46 -
Re-position video clips in Vegas 7 to be aligned.
By brek in forum EditingReplies: 5Last Post: 10th Jun 2008, 04:05 -
Flv encoder that gives precise control over A/V parameters?
By brassplyer in forum Video Streaming DownloadingReplies: 4Last Post: 3rd May 2008, 21:39 -
How to Make Slideshow DVD with Slide Duration Control in the Playback?
By zeeman in forum Authoring (DVD)Replies: 6Last Post: 19th Jan 2008, 13:07