[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 842
  • Last Modified:

How do I copy the video stream from a buffer of webcam in C++ under Windows?

I work on a C++ project similar to SplitCam - http://www.splitcamera.com/ and I couldn't find out any way to create DirectShow Source Filter without input pins, that distributes video stream from a webcam to its output pin. I can neither find any API to initiate connection with a webcam from my filter, nor copy the video stream from a buffer of webcam to some temporary destination such as shared memory to use IPC. Please help.
0
mkruebl
Asked:
mkruebl
  • 2
  • 2
1 Solution
 
mkrueblAuthor Commented:
Yes, DirectShow can easily capture frames, but I need to access pixels of each frame to store them into shared memory.

Currently, I generate random frame each time it is called:

// This is where we insert the DIB bits into the video stream.
// FillBuffer is called once for every sample in the stream.
HRESULT MyOutputPin::FillBuffer(IMediaSample *pSample) {
      log_message("MyOutputPin::FillBuffer()");
      CheckPointer(pSample, E_POINTER);
    BYTE *pData;
    long lDataLen;

      pSample->GetPointer(&pData);
      lDataLen = pSample->GetSize();

      ZeroMemory(pData, lDataLen);
      {
          CAutoLock cAutoLockShared(&m_cSharedState);
            long i;
            for (i = 0; i < lDataLen; i++) {
                  if (i & 1) {
                        pData[i] = rand() % 255;
                  } else {
                        pData[i] = rand() % 255;
                  }
            }
    }

    pSample->SetSyncPoint(TRUE);
    return S_OK; // S_FALSE End of stream, S_OK = filled
}

It will look similarly to http://www.eggheadcafe.com/software/aspnet/31543459/source-filters-fillbuffe.aspx when you tell me how to get BYTE *pData from each frame grabbed from a webcam.
0
 
vhpgomesCommented:
You can use SampleGrabber to access pixels of each frame.

See the code below... I stripped all error checking for brevity... i may have striped something else by mistake... but it may give you some directions.

The 'mDShowSampleGrabberCB' object will be called every frame, as soon as a new frame is available.




//Callback class
class SampleGrabberCallback : public ISampleGrabberCB
{
public:
    SampleGrabberCallback(void)
    {
        referenceCount = 0;
    }
 
    /// Mandatory overrides
    STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject)
    {
        *ppvObject = static_cast<ISampleGrabberCB*>(this);
        return S_OK;
    }
 
    STDMETHODIMP_(ULONG) AddRef(void)  { return ++referenceCount; }
    STDMETHODIMP_(ULONG) Release(void)
    {
        if(referenceCount == 1)
        {
            // clean Up
        }
        return --referenceCount;
    }
 
    // We receive here a pointer to the original buffer (we need to make a copy)
    STDMETHODIMP SampleCB(double Time, IMediaSample* pSample)
    {
        unsigned char* ptrBuffer;
 
        HRESULT hr = pSample->GetPointer(&ptrBuffer);
 
        if(hr == S_OK)
        {
            // do something with the buffer here...
            // something like:
            //
            // int bufferLength = pSample->GetActualDataLength();
            // memcpy(mybuffer,ptrBuffer,bufferLength);
        }
 
        return S_OK;
    }
 
    // We won't use this... it returns a copy so it has more overhead
    STDMETHODIMP BufferCB(double Time, BYTE* pBuffer, long BufferLen){
       return E_NOTIMPL;
    }
 
    unsigned int referenceCount;
 
};  // SampleGrabberCallback
 
 
 
///
///
/// then, somewhere in your code
///
///
 
(...)
// Create the sample grabber filter and add it to the graph
IBaseFilter* mDShowFilterGrabber;
hr = CoCreateInstance(CLSID_SampleGrabber,NULL,
                      CLSCTX_INPROC_SERVER,IID_IBaseFilter,
                      (void**)&mDShowFilterGrabber);
 
hr = pGraph->AddFilter(mDShowFilterGrabber,L"Sample Grabber");
 
// Create the sample grabber
ISampleGrabber* mDShowSampleGrabber;
hr = mDShowFilterGrabber->QueryInterface(IID_ISampleGrabber,
                                        (void**)&mDShowSampleGrabber);
mDShowSampleGrabber->SetOneShot(FALSE);
mDShowSampleGrabber->SetBufferSamples(FALSE);
 
// Sets the sample grabber media type
AM_MEDIA_TYPE mt;
ZeroMemory(&mt, sizeof(AM_MEDIA_TYPE));
mt.majortype = MEDIATYPE_Video;
mt.subtype = MEDIASUBTYPE_RGB24;
hr = mDShowSampleGrabber->SetMediaType(&mt);
 
// Create the callback
SampleGrabberCallback* mDShowSampleGrabberCB;
mDShowSampleGrabberCB = new SampleGrabberCallback();
 
//Tell the grabber to use our callback function
//0 is for SampleCB and 1 for BufferCB
hr = mDShowSampleGrabber->SetCallback(mDShowSampleGrabberCB,0);

Open in new window

0
 
mkrueblAuthor Commented:
That's exactly it! Thank you so much vhpgomes.
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 2
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now