Sample Grabber misses samples
Hi All,
I'm struggling to work out why the sample grabber sometimes misses samples.
I have a filter graph which consists of a DV camera as source, dv splitter, dv decoder and a sample grabber on the video chain through to a video renderer, and the audio chain terminates in a null renderer.
I'm using the sample grabber's buffercb method, which includes a double SampleTime parameter. I write a simple callback which basically divides this double value by 0.040 (my video is 25Hz, 40ms/frame) to get a frame number. I'm then just storing this frame number in an array. I'm not doing anything else in the callback, so it's very lean and mean
After ~50 minutes of video, I dump the array contents out so i can analyse what frames i received a callback for. About 8% are missing, thus my callback is not getting called about 8% of the time.
IAMDroppedFrames does not show any dropped frames after my callback starts; my cpu utilization never exceeds 10%, and my system is a dual core athlon x2 4200+, with 2Gb RAM. I'm not touching anything on the PC while it runs.
Has anyone got any idea why i'm missing samples? what happens to them? how can i get to look at all of them?
Any help much appreciated.
Slip
[1268 byte] By [
Slippyr4] at [2007-12-22]
Well, a couple of thoughts:
- It seems unlikely that sample grabber is "missing" the frames. All the frames that go through the graph will go thru the sample grabber.
- Doing the division against the frame time may not give perfect results. Capture devices aren't always religious about their timestamps.
- Have you tried just using the camera's utils to copy the video, then use another tool to count frames and compare that to the count of times your cb is called?
LGS at 2007-8-30 >

Ok, I've reimplemented my callback a little differently and I am still missing frames.
My source is a DV VCR. The tape i'm playing has video footage, and i correspondingly have an array of frame numbers that i need to capture, starting from a particular point on the tape. The frame numbers go along the lines of 0,145,342,711, etc. There are a total of about 12,000 frames to capture, which span over about 56 minutes of tape.
Further to the above posts, I decided to reimplement the code, using SampleCB instead of BufferCB. I reason that I can increment a (static volatile) frame counter member variable, and compare the value of this with the frame number i'm looking to capture to decide whether to capture it or not.
Additionally, checking events for quality change events, and checking every sample's IsDiscontinuity property, should highlight if something has gone wrong.
Here is my callback, in kind of made up code (it's actually some hacked c# (although I am experiencing these problems both in c# and also c++).
HRESULT ISampleGrabberCB.SampleCB(double SampleTime, IMediaSample pSample)
{
// if this is the first callback, see how many dropped frames we've had so far
// DV drops frames a lot when you first play the tape, or rewind or whatever. so often
// the dropped frame count is not zero the first time the callback runs
if (m_callbackCount == 0)
{
IAMDroppedFrames.GetNumDropped(out nDroppedAtStart);
IAMDroppedFrames.GetNumNotDropped(out nNotDroppedAtStart);
}
// log stuff if this sample is a discontinuity
if (pSample.IsDiscontinuity() == S_OK)
{
int dropped, notdropped;
IAMDroppedFrames.GetNumDropped(out dropped);
IAMDroppedFrames.GetNumNotDropped(out notdropped);
LogWriter.Instance.WriteLine("DISCONTINUITY: " + (dropped - nDroppedAtStart) + " dropped, " + (notdropped - nNotDroppedAtStart) + " not dropped");
}
// check events
int hr; int p1, p2;
EventCode ec;
for (hr = IMediaEvent.GetEvent(out ec, out p1, out p2, 0); hr >= 0; hr = IMediaEvent.GetEvent(out ec, out p1, out p2, 0))
{
if (ec == EventCode.QualityChange)
{
int dropped, notdropped;
IAMDroppedFrames.GetNumDropped(out dropped);
IAMDroppedFrames.GetNumNotDropped(out notdropped);
LogWriter.Instance.WriteLine("QUALITY CHANGE: " + (dropped - nDroppedAtStart) + " dropped, " + (notdropped - nNotDroppedAtStart) + " not dropped");
}
}
// check if we want this frame
// m_framesToGrab is an int array containing frames numbers i want to capture, starting from 0
if (m_framesToGrab[m_index].Frame <= m_callbackCount)
{
m_index++;
// chopped code here copied the data from the buffer and added it to a FIFO queue being processed
// by another (low priority) thread
}
// incremement the callback count
m_callbackCount++;
return S_OK;
}
So when running this code, in my mind I should either get a look at every single frame, or my log should show that there were discontinuities and/or quality changes - representing missing calls of my SampleCB
However, when i run the code against my 56 minute tape, i get no evidence in the log of discontinuities or quality changes, yet I know the capture is incorrect because the capture completes about 20 seconds after it should do. (I can tell from the content of the video when the capture ought to have ended). So, there is a drift in 56 minutes of tape of about 20 seconds - around 0.66 % of frames are evidentally not calling my callback.
How can I get round this?
< tearing my hair out>
cheers
slip
I'm trying to understand this paragraph:
However, when i run the code against my 56 minute tape, i get no evidence in the log of discontinuities or quality changes, yet I know the capture is incorrect because the capture completes about 20 seconds after it should do. (I can tell from the content of the video when the capture ought to have ended). So, there is a drift in 56 minutes of tape of about 20 seconds - around 0.66 % of frames are evidentally not calling my callback.
Can you describe this 20 seconds again? You capture 56 minutes of video, call IMediaControl::Stop, and, what, it takes 20 seconds to stop the capture? The capture file shows a length of 56:20?
LGS at 2007-8-30 >

No, not quite.
First, remember i'm not capturing to a file. My graph runs from DV camera through the sample grabber, to a video renderer. My output is jpeg encoded frames that correspond to frames in the list of frames i want.
I regard capture to start at frame 0, and it's "finished" when i've grabbed the last of the frames in my list of frames.
The list of frames contains about 12,000 entries, and the highest video frame number i need to capture is 84,733. The video is PAL, progressive scan, 25.0 fps, so in real time that corresponds to 56:29.08 . So, once I start capturing, my process should be complete after that period of time.
However, it's not. 56:29 after i start capturing, my SampleCB implementation doesn't think it's had 84,733 frames. It takes about another 20 seconds before the counter in SampleCB increments high up to 84,733.
Does that make any sense?
slip