HELP! Text overlay on live video



Hi,

I really need your help to solve the problem. I want to do an application
which is for live video streaming with time frame on the video.

Followings is the function i modified from SDK sample.


BOOL BuildCaptureGraph()
{
USES_CONVERSION;
int cy, cyBorder;
HRESULT hr;
AM_MEDIA_TYPE *pmt=0;

// we have one already
if(m_sCap.bCaptureGraphBuilt)
{
DEBUGLOG(_T("Capture Graph Built"));
return TRUE;
}

// No rebuilding while we're running
if(m_sCap.bCapturing || m_sCap.bPreviewing)
{
DEBUGLOG(_T("Capturing or Previewing is running"));
return FALSE;
}

// We don't have the necessary capture filters
if(m_sCap.pVCap == NULL)
{
DEBUGLOG(_T("Capture filter is null"));
return FALSE;
}

// we already have another graph built... tear down the old one
if(m_sCap.bPreviewGraphBuilt)
TearDownGraph();

//
// We need a rendering section that will write the capture file out in
// AVI file format
//

GUID guid;
if( m_sCap.bMPEG2 )
{
guid = MEDIASUBTYPE_Mpeg2;
}
else
{
guid = MEDIASUBTYPE_Avi;
}

//
// Render the video capture and preview pins - even if the capture
// filter only has a capture pin (and no preview pin) this should
// work, because the capture graph builder will use a smart tee filter
// to provide both capture and preview. We don't have to worry. It
// will just work

// NOTE that we try to render the interleaved pin before the video
// pin, because if BOTH exist, it's a DV filter and the only way to get
// the audio is to use the interleaved pin. Using the Video pin on a
// DV filter is only useful if you don't want the audio.

IBaseFilter *pVideoEncoderFilter=NULL;
IH263Enc *pVidEncPropData=NULL;
IBaseFilter *pRTPPacketizerFilter=NULL;
IRtpPacket *pVidPackPropData=NULL;
IBaseFilter *pRTPSenderFilter=NULL;
IRtpSend *pVidSendPropData=NULL;

IBaseFilter *pVideoRTPPacketizerFilter = NULL;
IBaseFilter *pVideoRTPSenderFilter = NULL;

AM_MEDIA_TYPE H263pmt;
bool bHasVideo = true;

IPin *pVideoPacketizerInPin = NULL;
IPin *pVideoPacketizerOutPin = NULL;
IPin *pVideoSenderInPin = NULL;

PIN_INFO PinInfo;

IBaseFilter *pGrabberF = NULL;
ISampleGrabber *pGrabber;
if (m_bTextOverlay)
{
hr = S_OK;
hr = CoCreateInstance(CLSID_SampleGrabber, NULL,
CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pGrabberF);

if (FAILED(hr))
{
// Return an error.
}

hr = m_sCap.pFg->AddFilter(pGrabberF, L"Sample Grabber 1");
if (FAILED(hr))
{
// Return an error.
return hr;
}

pGrabberF->QueryInterface(IID_ISampleGrabber, (void**)&pGrabber);

AM_MEDIA_TYPE mt;

CMediaType cm;
cm.SetType(&MEDIATYPE_Video);
cm.SetSubtype(&GUID_NULL );
cm.SetFormatType(&FORMAT_VideoInfo);
hr = pGrabber->SetMediaType(&cm);
}

hr = CoCreateInstance(CLSID_H263Filter, NULL, CLSCTX_INPROC_SERVER,
IID_IBaseFilter, (void**)&pVideoEncoderFilter);

if (FAILED(hr))
{
DEBUGLOG(_T("Failed to init h.263 encoder"));
return hr;
}
DEBUGLOG(_T("Init h.263 encoder"));

hr = m_sCap.pFg->AddFilter(pVideoEncoderFilter, L"Video Encoder");

if (FAILED(hr))
{
DEBUGLOG(_T("Failed to add h.263 encoder"));
return hr;
}
DEBUGLOG(_T("Added h.263 encoder"));

hr = CoCreateInstance (CLSID_RtpPacketFilter, NULL,
CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pRTPPacketizerFilter);
if (FAILED(hr))
{
DEBUGLOG(_T("Failed to init RTP packetizer filter"));
return hr;
}
DEBUGLOG(_T("init RTP packetizer filter"));

hr = m_sCap.pFg->AddFilter(pRTPPacketizerFilter, L"RTP Packetizer");
if (FAILED(hr))
{
DEBUGLOG(_T("Failed to add RTP Packetizer"));
return hr;
}
DEBUGLOG(_T("add RTP Packetizer"));

pRTPPacketizerFilter->Release();
pRTPPacketizerFilter = NULL;

hr = CoCreateInstance (CLSID_RtpSenderFilter, NULL,
CLSCTX_INPROC_SERVER, IID_IBaseFilter,
(void**)&pRTPSenderFilter);
if (FAILED(hr))
{
DEBUGLOG(_T("Failed to init RTP Sender"));
return hr;
}
DEBUGLOG(_T("init RTP Sender"));

hr = m_sCap.pFg->AddFilter(pRTPSenderFilter, L"RTP Sender");
if (FAILED(hr))
{
DEBUGLOG(_T("Failed to add RTP Sender"));
return hr;
}
DEBUGLOG(_T("Add RTP Sender"));

pRTPSenderFilter->Release();
pRTPSenderFilter = NULL;

IEnumPins *pEnumPin = NULL;
IPin *pPinA = NULL;
IPin *pPinC = NULL;
hr = m_sCap.pVCap->EnumPins(&pEnumPin);
if (FAILED(hr))
{
DEBUGLOG(_T("Failed to enum video capture pin"));
return FALSE
}

while (pEnumPin->Next(1, &pPinA, NULL) == S_OK)
{
hr = pPinA->QueryPinInfo(&PinInfo);
CString str(PinInfo.achName);
TRACE(_T("%s\n"), str);

if (hr == S_OK)
{
if (strcmp(PinInfo.achName, "Capture") == 0)
{
hr = pPinA->ConnectedTo(&pPinC);
if (PinInfo.dir == PINDIR_OUTPUT && hr == VFW_E_NOT_CONNECTED)
{
hr = m_sCap.pFg->Render(pPinA);

pEnumPin->Release();
hr = m_sCap.pVCap->EnumPins(&pEnumPin);
if (FAILED(hr))
{
DEBUGLOG(_T("Failed to enum video capture pin in the loop"));
return FALSE
}
}
PinInfo.pFilter->Release();
pPinA->Release();

if (pPinC)
pPinC->Release();
}
}
}

pEnumPin->Release();

TRACE(_T("Enumerating Filters...............................\n"));
EnumFilters(m_sCap.pFg);

IPin *pVideoOutPin = GetPin(pVideoEncoderFilter, PINDIR_OUTPUT);
if (!pVideoOutPin)
{
DEBUGLOG(_T("Failed to get pin for video out"));
return hr;
}

hr = pVideoOutPin->ConnectionMediaType(&H263pmt);
if (VFW_E_NOT_CONNECTED == hr)
{
bHasVideo = false;

//Error
DEBUGLOG(_T("VFW E Not connected"));
return hr;
}
else if (FAILED(hr))
{
DEBUGLOG(_T("Failed to get connection media type"));
return hr;
}
else
{
//Settings
hr = pVideoEncoderFilter->Release();
pVideoEncoderFilter = NULL;

hr = pVideoOutPin->Release();
pVideoOutPin = NULL;
}

if (bHasVideo)
{
hr = pVidEncPropData->Release();
pVidEncPropData = NULL;

hr = pVidPackPropData->Release();
pVidPackPropData = NULL;

hr = pVidSendPropData->Release();
pVidSendPropData = NULL;
}

if( !m_sCap.bMPEG2 )
{
if(m_sCap.bWantPreview)
{
hr = m_sCap.pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Interleaved,
m_sCap.pVCap, NULL, NULL);
if(hr == VFW_S_NOPREVIEWPIN)
{
// preview was faked up for us using the (only) capture pin
m_sCap.bPreviewFaked = TRUE;
}
else if(hr != S_OK)
{
hr = m_sCap.pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Video,
m_sCap.pVCap, NULL, NULL);
if(hr == VFW_S_NOPREVIEWPIN)
{
// preview was faked up for us using the (only) capture
pin
m_sCap.bPreviewFaked = TRUE;
}
else if(hr != S_OK)
{
ErrMsg(_T("Cannot render video preview stream
[BuildCaptureGraph]"));
DEBUGLOG(_T("Setup Capture failed"));
TearDownGraph();
return FALSE;
}
}
}
}
else
{
CComPtr< IBaseFilter > sink;
if( &m_sCap.pSink )
{
m_sCap.pSink->QueryInterface( IID_IBaseFilter,
reinterpret_cast<void **>( &sink ) );

}

hr = m_sCap.pBuilder->RenderStream(NULL,
&MEDIATYPE_Stream,
m_sCap.pVCap, NULL, sink);
}

if (m_bTextOverlay)
{
hr = pGrabber->GetConnectedMediaType( &g_StillMediaType );
VIDEOINFO* pVI = (VIDEOINFO*) g_StillMediaType.pbFormat;

pGrabber->SetBufferSamples(FALSE);
pGrabber->SetOneShot(FALSE);
pGrabber->SetCallback(&g_StillCapCB, 0);
}

//
// Get the preview window to be a child of our app's window
//

// This will find the IVideoWindow interface on the renderer. It is
// important to ask the filtergraph for this interface... do NOT use
// ICaptureGraphBuilder2::FindInterface, because the filtergraph needs to
// know we own the window so it can give us display changed messages, etc.

if(!m_sCap.bMPEG2 && m_sCap.bWantPreview)
{
hr = m_sCap.pFg->QueryInterface(IID_IVideoWindow, (void
**)&m_sCap.pVW);
if(hr != NOERROR && m_sCap.bWantPreview)
{
ErrMsg(_T("This graph cannot preview [BuildCaptureGraph]"));
}
else if(hr == NOERROR)
{
RECT rc;
m_sCap.pVW->put_Owner((OAHWND)m_hWnd); // We own the window now
m_sCap.pVW->put_WindowStyle(WS_CHILD); // you are now a child

// give the preview window all our space but where the status
bar is
GetClientRect(&rc);
cyBorder = GetSystemMetrics(SM_CYBORDER);
cy = StatusGetHeight() + cyBorder;
rc.bottom -= cy;

m_sCap.pVW->SetWindowPosition(0, 0, rc.right, rc.bottom); // be
this big
m_sCap.pVW->put_Visible(OATRUE);
}
}

// now ask the filtergraph to tell us when something is completed or
aborted
// (EC_COMPLETE, EC_USERABORT, EC_ERRORABORT). This is how we will find
out
// if the disk gets full while capturing
hr = m_sCap.pFg->QueryInterface(IID_IMediaEventEx, (void **)&m_sCap.pME);
if(hr == NOERROR)
{
m_sCap.pME->SetNotifyWindow((OAHWND)m_hWnd, WM_FGNOTIFY, 0);
}

// potential debug output - what the graph looks like
// DumpGraph(gcap.pFg, 1);

// Add our graph to the running object table, which will allow
// the GraphEdit application to "spy" on our graph
#ifdef REGISTER_FILTERGRAPH
hr = AddGraphToRot(m_sCap.pFg, &g_dwGraphRegister);
if(FAILED(hr))
{
ErrMsg(_T("Failed to register filter graph with ROT
[BuildCaptureGraph] hr=0x%x"), hr);
g_dwGraphRegister = 0;
}
#endif

// All done.
m_sCap.bCaptureGraphBuilt = TRUE;
return TRUE;
}


What I get in the GraphEdit is :
Capture ---> SampleGrabber->Color Space Converter->Video Renderer
Preview --> AVI Decompressor -> Video Renderer 001

and Unconnected filters:
Color Space Converter->Video Encoder->RTP Packetizer->RTP Sender

My concern is how to make the Sample Grabber connect to Video Encoder???

Any error in the code? Please help me to point out the error.


All helps are appreciate! Thanks
.



Relevant Pages

  • Re: DirectShow @ WM 5.0: Capture camera to memory?
    ... The still image pin will most likely expose higher resolutions than ... the capture pin which could negativly impact your performance, ... You'll need to create a sink filter that does your processing, RGB video ...
    (microsoft.public.pocketpc.developer)
  • Re: Converting YUY2 format video to AVI
    ... Windows media encoder sdk to convert avi to wmv. ... your H.264 video decoder output in another format, ... His capture card is the following - ... filter graph instance in the "Running Object Table", ...
    (rec.video.desktop)
  • AVI Decompressor & Smart Tee question
    ... video capture: ... need a preview (Video Window) ... custom filter used to buffer/delay the samples to be write (between ... capture pin of Smart Tee & AVI Mux) ...
    (microsoft.public.win32.programmer.directx.video)
  • Re: InfTee doesnt work with Video Mixing Renderer 9
    ... > with odd video sizes, e.g. the video must correspond to the ... downstream filter. ... >> When I add the InfTee filter, it cannot connect to VMR9 directly. ... >> Here pPin is the receiving pin and pTee->m_pAllocator ...
    (microsoft.public.multimedia.directx.dshow.programming)
  • Re: Video Capture Performance with directshow
    ... As for your question about video encoding, that is similar what we're doing ... The output pin on the filter is running ... so it slowly feeds data into the WMV encoder as ... delved into it a bit and found that it was a capture filter from HTC ...
    (microsoft.public.pocketpc.developer)

Quantcast