-
6 second delay in video
I built a filter graph in directshow and can get the video feed started, but it seems that teh images I am reciving from the sample grabber are delayed 6 seconds behind when the events actually take place. That is, if I stick my hand in front of the camera, the image of my hand doesnt appear until 6 seconds later. I used the SetSyncSource(NULL) method to make all teh filters run as fast as possible, btu there is still the 6 second buffering delay. The source filter is created by -
Code:
IBaseFilter *pSrc;
hr = pGraph->AddSourceFilter(L"http://192.168.0.115/img/video.asf", L"Source", &pSrc);
Hopefully someone can help me to reduce this buffering delay?
-
OK, I think I got it down to somethign in the sample grabber buffering scheme forcing this lag. So I want to set up the callback functionality, but it seems that there is far more to settign up the callback class that MSDN implies.
here is what I have so far -
Code:
// Set the sample grabber to callback mode
MyCallBack pCallBack;
pGrabber->SetBufferSamples(FALSE);
pGrabber->SetCallback((ISampleGrabberCB*)&pCallBack , 0);
Code:
class MyCallBack {
public:
STDMETHODIMP_(ULONG) AddRef() { return 2; }
STDMETHODIMP_(ULONG) Release() { return 1; }
HRESULT BufferCB(double SampleTime,BYTE *pBuffer,long BufferLen);
STDMETHODIMP SampleCB (double n,IMediaSample *pms){
BYTE* pBuffer;
DWORD BuffLen;
BuffLen = pms->GetActualDataLength();
pms->GetPointer(&pBuffer);
CopyMemory(&DrawBuffer[54] , pBuffer , BuffLen);
return 0;
}
};
the problem im having is as soon as I call setcallback, the application crashes.
-
You should pass some real function pointer (that will be called on event), not just an uninitialized pointer with the appropriate type
-
How is the function not valid? I instantiated it with
Code:
MyCallBack pCallBack;
So &pCallBack should be a valid pointer, or is it friday and im dense...
-
MyCallBack pCallBack; is not a function
Code:
int myfunction()
{
return 0;
}
is a function
Don't you notice the difference?
-
the method requires thet you pass a pointer to a class that implements the function, not the function itself. You had me going there for a minute. Its some peculiar directshow thingy. Anyhow, I got it working by borrowing some code from MSDN. Unfortunately that didnt solve the problem either. There is still a 6 second delay in the video. I even enumerated all the filters and set their reference clocks to NULL, still no change.
-
Make sure you have set the interval for the multi-media timer. It defaults to 5 ms but can go as low as 1 ms. I doubt this is the issue but it's a start.
I've used DirectShow before and did not experience this type of problem. By no means am I a DirectShow expert and don't plan on ever being one since they are probably going to get rid of it.
-
Shouldn't MyCallback inherit from ISampleGrabberCB? You are currently casting your callback class to an interface which it doesn't inherit from.
-
The class im using directly implements ISampleGrabberCB, so no inheritance needed.
Code:
extern BYTE DrawBuffer[];
extern AM_MEDIA_TYPE mt;
#ifndef CALLBACK_CLASS
#define CALLBACK_CLASS
// Class to hold the callback function for the Sample Grabber filter.
class SampleGrabberCallback : public ISampleGrabberCB {
public:
// Fake referance counting.
STDMETHODIMP_(ULONG) AddRef() { return 1; }
STDMETHODIMP_(ULONG) Release() { return 2; }
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject){
if (NULL == ppvObject) return E_POINTER;
if (riid == __uuidof(IUnknown)){
*ppvObject = static_cast<IUnknown*>(this);
return S_OK;
}
if (riid == __uuidof(ISampleGrabberCB)){
*ppvObject = static_cast<ISampleGrabberCB*>(this);
return S_OK;
}
return E_NOTIMPL;
}
STDMETHODIMP SampleCB(double Time, IMediaSample *pSample){
BYTE* pBuffer;
DWORD dwLength;
dwLength = pSample->GetActualDataLength();
pSample->GetPointer(&pBuffer);
if(pSample->IsPreroll() == S_OK){
return S_OK;
}
CopyMemory(&DrawBuffer[54] , pBuffer , dwLength);
return S_OK;
}
STDMETHODIMP BufferCB(double Time, BYTE *pBuffer, long BufferLen){
if ((mt.majortype != MEDIATYPE_Video) || (mt.formattype != FORMAT_VideoInfo) || (mt.cbFormat < sizeof(VIDEOINFOHEADER)) || (mt.pbFormat == NULL)){
return VFW_E_INVALIDMEDIATYPE;
}
HANDLE hf = CreateFile("C:\\Example.bmp", GENERIC_WRITE,
FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
if (hf == INVALID_HANDLE_VALUE){
return E_FAIL;
}
long cbBitmapInfoSize = mt.cbFormat - SIZE_PREHEADER;
VIDEOINFOHEADER *pVideoHeader = (VIDEOINFOHEADER*)mt.pbFormat;
BITMAPFILEHEADER bfh;
ZeroMemory(&bfh, sizeof(bfh));
bfh.bfType = 'MB'; // Little-endian for "MB".
bfh.bfSize = sizeof( bfh ) + BufferLen + cbBitmapInfoSize;
bfh.bfOffBits = sizeof( BITMAPFILEHEADER ) + cbBitmapInfoSize;
// Write the file header.
DWORD dwWritten = 0;
WriteFile( hf, &bfh, sizeof( bfh ), &dwWritten, NULL );
WriteFile(hf, HEADER(pVideoHeader), cbBitmapInfoSize, &dwWritten, NULL);
WriteFile( hf, pBuffer, BufferLen, &dwWritten, NULL );
CloseHandle( hf );
return S_OK;
}
};
#endif
-
OK, I solved the problem somewhat. Since I am using the callback method and gettign the actual sample, I just modified the presentation time for each sample and whaddaya know, it worked. For each sample I just subtracted 4.6 seconds from its start and finish time and it brought the delay down to a reasonable amount. This is still a bit wierd though, as i thought the reference clocks where all set to null to run as fast as possible, and im directly taking the image data from the samples when it gets sent to me, All i can think of is that the NULL render filter is somehow backing up the whole process.