views:

378

answers:

2

Is there a way to detect that a DirectShow filtergraph has reached the end of its file? By end of its file, I mean that a filtergraph with a SampleGrabber filter will never receive another SampleCB call.

Here are some things that don't work:

  • Trust IMediaDet::get_StreamLength (it's often says there are more frames in a video than really exist)
  • Trust IMediaSeeking::GetDuration (it's consistent with IMediaDet, +/- one frame)
  • Use IMediaControl::GetState (the filtergraph remains running even if all frames have already been processed from a file)

Background:

I am doing video processing and I have a class that creates a filtergraph with a SampleGrabber. Whenever SampleGrabber::SampleCB is called, I block it with a mutex so I can run the filtergraph in pull mode. When I'm ready for another frame, I unblock the mutex in my main thread and wait for SampleGrabber::SampleCB to send me a signal that it's done. For some videos, IMediaDet::get_StreamLength tells me that the video has more frames than really exist. Once I've extracted the final frame and request one more than actually exists, the main thread then blocks forever because SampleGrabber::SampleCB will never get called again. I'd like to be able to detect when SampleGrabber::SampleCB will never be called for file sources. Applications like Windows Media Player are able to somehow do this because the GUI reports that the video has ended after the last real frame, so apparently there's a way to do this.

EDIT:

I'm using WaitForSingleObject to implement the main thread blocking. The workaround that I've been using so far is to do what Greg suggested: have a finite timeout. Unfortunately, this gets a little tricky. The wait can fail for many reasons such as a true eof, slow network filesystem, lost network connection, slow decoder, etc.

A: 

Assuming the main thread is blocking on WaitForSingleObject, could you not specify a timeout for the wait? Then if the wait returns because it has timed out rather than because it has received a signal you'll know it's the last frame.

Greg Beech
That's what I've been doing so far. Unfortunately, the wait can fail for several reasons (true eof, slow network filesystem, lost network connection, slow decoder, etc.).
Mr Fooz
Yeah that's true - unfortunately it's the best solution I've found because, as you have also found, IMediaDet never quite returns the right information, especially if there are non-Microsoft filters such as ffdshow in the graph (I've also been doing a lot of frame grabbing recently).
Greg Beech
+1  A: 

Maybe using the IMediaEventEx interface? One of the event codes is EC_COMPLETE documented as 'All data from a particular stream has been rendered.'

David Rodríguez - dribeas