Handle many more edge cases in dshowvideosink.

Instrument various codepaths with debug messages.
Handle (as best as I could see how - it's pretty nasty) moving a video
window to another monitor.
Add listening for directshow events.
This commit is contained in:
Michael Smith 2009-02-04 17:50:51 -08:00
parent e3fcf51e2c
commit 2e401cc71d
4 changed files with 2045 additions and 1833 deletions

View File

@ -1,281 +1,414 @@
/* GStreamer /* GStreamer
* Copyright (C) 2008 Pioneers of the Inevitable <songbird@songbirdnest.com> * Copyright (C) 2008 Pioneers of the Inevitable <songbird@songbirdnest.com>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. * version 2 of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details. * Library General Public License for more details.
* *
* You should have received a copy of the GNU Library General Public * You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the * License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
#include "dshowvideofakesrc.h" #include "dshowvideofakesrc.h"
// {A0A5CF33-BD0C-4158-9A56-3011DEE3AF6B} GST_DEBUG_CATEGORY_EXTERN (dshowvideosink_debug);
const GUID CLSID_VideoFakeSrc = #define GST_CAT_DEFAULT dshowvideosink_debug
{ 0xa0a5cf33, 0xbd0c, 0x4158, { 0x9a, 0x56, 0x30, 0x11, 0xde, 0xe3, 0xaf, 0x6b } };
// {A0A5CF33-BD0C-4158-9A56-3011DEE3AF6B}
/* output pin*/ const GUID CLSID_VideoFakeSrc =
VideoFakeSrcPin::VideoFakeSrcPin (CBaseFilter *pFilter, CCritSec *sec, HRESULT *hres): { 0xa0a5cf33, 0xbd0c, 0x4158, { 0x9a, 0x56, 0x30, 0x11, 0xde, 0xe3, 0xaf, 0x6b } };
CBaseOutputPin("VideoFakeSrcPin", pFilter, sec, hres, L"output")
{ /* output pin*/
} VideoFakeSrcPin::VideoFakeSrcPin (CBaseFilter *pFilter, CCritSec *sec, HRESULT *hres):
CDynamicOutputPin("VideoFakeSrcPin", pFilter, sec, hres, L"output")
VideoFakeSrcPin::~VideoFakeSrcPin() {
{ }
}
VideoFakeSrcPin::~VideoFakeSrcPin()
HRESULT VideoFakeSrcPin::GetMediaType(int iPosition, CMediaType *pMediaType) {
{ }
GST_DEBUG ("GetMediaType(%d) called", iPosition);
if(iPosition == 0) { HRESULT VideoFakeSrcPin::GetMediaType(int iPosition, CMediaType *pMediaType)
*pMediaType = m_MediaType; {
return S_OK; GST_DEBUG ("GetMediaType(%d) called", iPosition);
} if(iPosition == 0) {
*pMediaType = m_MediaType;
return VFW_S_NO_MORE_ITEMS; return S_OK;
} }
/* This seems to be called to notify us of the actual media type being used, return VFW_S_NO_MORE_ITEMS;
* even though SetMediaType isn't called. How bizarre! */ }
HRESULT VideoFakeSrcPin::CheckMediaType(const CMediaType *pmt)
{ /* This seems to be called to notify us of the actual media type being used,
GST_DEBUG ("CheckMediaType called: %p", pmt); * even though SetMediaType isn't called. How bizarre! */
HRESULT VideoFakeSrcPin::CheckMediaType(const CMediaType *pmt)
/* The video renderer will request a different stride, which we must accept. {
* So, we accept arbitrary strides (and do memcpy() to convert if needed), GST_DEBUG ("CheckMediaType called: %p", pmt);
* and require the rest of the media type to match
*/ /* The video renderer will request a different stride, which we must accept.
if (IsEqualGUID(pmt->majortype,m_MediaType.majortype) && * So, we accept arbitrary strides (and do memcpy() to convert if needed),
IsEqualGUID(pmt->subtype,m_MediaType.subtype) && * and require the rest of the media type to match
IsEqualGUID(pmt->formattype,m_MediaType.formattype) && */
pmt->cbFormat >= m_MediaType.cbFormat) if (IsEqualGUID(pmt->majortype,m_MediaType.majortype) &&
{ IsEqualGUID(pmt->subtype,m_MediaType.subtype) &&
if (IsEqualGUID(pmt->formattype, FORMAT_VideoInfo)) { IsEqualGUID(pmt->formattype,m_MediaType.formattype) &&
VIDEOINFOHEADER *newvh = (VIDEOINFOHEADER *)pmt->pbFormat; pmt->cbFormat >= m_MediaType.cbFormat)
VIDEOINFOHEADER *curvh = (VIDEOINFOHEADER *)m_MediaType.pbFormat; {
if (IsEqualGUID(pmt->formattype, FORMAT_VideoInfo)) {
if ((memcmp ((void *)&newvh->rcSource, (void *)&curvh->rcSource, sizeof (RECT)) == 0) && VIDEOINFOHEADER *newvh = (VIDEOINFOHEADER *)pmt->pbFormat;
(memcmp ((void *)&newvh->rcTarget, (void *)&curvh->rcTarget, sizeof (RECT)) == 0) && VIDEOINFOHEADER *curvh = (VIDEOINFOHEADER *)m_MediaType.pbFormat;
(newvh->bmiHeader.biCompression == curvh->bmiHeader.biCompression) &&
(newvh->bmiHeader.biHeight == curvh->bmiHeader.biHeight) && if ((memcmp ((void *)&newvh->rcSource, (void *)&curvh->rcSource, sizeof (RECT)) == 0) &&
(newvh->bmiHeader.biWidth >= curvh->bmiHeader.biWidth)) (memcmp ((void *)&newvh->rcTarget, (void *)&curvh->rcTarget, sizeof (RECT)) == 0) &&
{ (newvh->bmiHeader.biCompression == curvh->bmiHeader.biCompression) &&
GST_DEBUG ("CheckMediaType has same media type, width %d (%d image)", newvh->bmiHeader.biWidth, curvh->bmiHeader.biWidth); (newvh->bmiHeader.biHeight == curvh->bmiHeader.biHeight) &&
(newvh->bmiHeader.biWidth >= curvh->bmiHeader.biWidth))
/* OK, compatible! */ {
return S_OK; GST_DEBUG ("CheckMediaType has same media type, width %d (%d image)", newvh->bmiHeader.biWidth, curvh->bmiHeader.biWidth);
}
else { /* OK, compatible! */
GST_WARNING ("Looked similar, but aren't..."); return S_OK;
} }
} else {
GST_WARNING ("Looked similar, but aren't...");
} }
GST_WARNING ("Different media types, FAILING!"); }
return S_FALSE;
} }
GST_WARNING ("Different media types, FAILING!");
HRESULT VideoFakeSrcPin::DecideBufferSize (IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) return S_FALSE;
{ }
ALLOCATOR_PROPERTIES properties;
GST_DEBUG ("Required allocator properties: %d, %d, %d, %d", HRESULT VideoFakeSrcPin::DecideBufferSize (IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
ppropInputRequest->cbAlign, ppropInputRequest->cbBuffer, {
ppropInputRequest->cbPrefix, ppropInputRequest->cBuffers); ALLOCATOR_PROPERTIES properties;
GST_DEBUG ("Required allocator properties: %d, %d, %d, %d",
ppropInputRequest->cbBuffer = m_SampleSize; ppropInputRequest->cbAlign, ppropInputRequest->cbBuffer,
ppropInputRequest->cBuffers = 1; ppropInputRequest->cbPrefix, ppropInputRequest->cBuffers);
/* First set the buffer descriptions we're interested in */ ppropInputRequest->cbBuffer = m_SampleSize;
HRESULT hres = pAlloc->SetProperties(ppropInputRequest, &properties); ppropInputRequest->cBuffers = 1;
GST_DEBUG ("Actual Allocator properties: %d, %d, %d, %d",
properties.cbAlign, properties.cbBuffer, /* First set the buffer descriptions we're interested in */
properties.cbPrefix, properties.cBuffers); HRESULT hres = pAlloc->SetProperties(ppropInputRequest, &properties);
GST_DEBUG ("Actual Allocator properties: %d, %d, %d, %d",
/* Then actually allocate the buffers */ properties.cbAlign, properties.cbBuffer,
pAlloc->Commit(); properties.cbPrefix, properties.cBuffers);
return S_OK; /* Then actually allocate the buffers */
} hres = pAlloc->Commit();
GST_DEBUG ("Allocator commit returned %x", hres);
STDMETHODIMP
VideoFakeSrcPin::Notify(IBaseFilter * pSender, Quality q) return S_OK;
{ }
/* Implementing this usefully is not required, but the base class
* has an assertion here... */ STDMETHODIMP
/* TODO: Map this to GStreamer QOS events? */ VideoFakeSrcPin::Notify(IBaseFilter * pSender, Quality q)
return E_NOTIMPL; {
} /* Implementing this usefully is not required, but the base class
* has an assertion here... */
STDMETHODIMP VideoFakeSrcPin::SetMediaType (AM_MEDIA_TYPE *pmt) /* TODO: Map this to GStreamer QOS events? */
{ return E_NOTIMPL;
m_MediaType.Set (*pmt); }
m_SampleSize = m_MediaType.GetSampleSize();
STDMETHODIMP VideoFakeSrcPin::SetMediaType (AM_MEDIA_TYPE *pmt)
GST_DEBUG ("SetMediaType called. SampleSize is %d", m_SampleSize); {
m_MediaType.Set (*pmt);
return S_OK; m_SampleSize = m_MediaType.GetSampleSize();
}
GST_DEBUG ("SetMediaType called. SampleSize is %d", m_SampleSize);
/* If the destination buffer is a different shape (strides, etc.) from the source
* buffer, we have to copy. Do that here, for supported video formats. return S_OK;
* }
* TODO: When possible (when these things DON'T differ), we should buffer-alloc the
* final output buffer, and not do this copy */ /* If the destination buffer is a different shape (strides, etc.) from the source
STDMETHODIMP VideoFakeSrcPin::CopyToDestinationBuffer (byte *srcbuf, byte *dstbuf) * buffer, we have to copy. Do that here, for supported video formats.
{ *
VIDEOINFOHEADER *vh = (VIDEOINFOHEADER *)m_MediaType.pbFormat; * TODO: When possible (when these things DON'T differ), we should buffer-alloc the
GST_DEBUG ("Rendering a frame"); * final output buffer, and not do this copy */
STDMETHODIMP VideoFakeSrcPin::CopyToDestinationBuffer (byte *srcbuf, byte *dstbuf)
byte *src, *dst; {
int dststride, srcstride, rows; VIDEOINFOHEADER *vh = (VIDEOINFOHEADER *)m_MediaType.pbFormat;
guint32 fourcc = vh->bmiHeader.biCompression; GST_DEBUG ("Rendering a frame");
/* biHeight is always negative; we don't want that. */ byte *src, *dst;
int height = ABS (vh->bmiHeader.biHeight); int dststride, srcstride, rows;
int width = vh->bmiHeader.biWidth; guint32 fourcc = vh->bmiHeader.biCompression;
/* YUY2 is the preferred layout for DirectShow, so we will probably get this /* biHeight is always negative; we don't want that. */
* most of the time */ int height = ABS (vh->bmiHeader.biHeight);
if ((fourcc == GST_MAKE_FOURCC ('Y', 'U', 'Y', '2')) || int width = vh->bmiHeader.biWidth;
(fourcc == GST_MAKE_FOURCC ('Y', 'U', 'Y', 'V')) ||
(fourcc == GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'))) /* YUY2 is the preferred layout for DirectShow, so we will probably get this
{ * most of the time */
/* Nice and simple */ if ((fourcc == GST_MAKE_FOURCC ('Y', 'U', 'Y', '2')) ||
int srcstride = GST_ROUND_UP_4 (vh->rcSource.right * 2); (fourcc == GST_MAKE_FOURCC ('Y', 'U', 'Y', 'V')) ||
int dststride = width * 2; (fourcc == GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y')))
{
for (int i = 0; i < height; i++) { /* Nice and simple */
memcpy (dstbuf + dststride * i, srcbuf + srcstride * i, srcstride); int srcstride = GST_ROUND_UP_4 (vh->rcSource.right * 2);
} int dststride = width * 2;
}
else if (fourcc == GST_MAKE_FOURCC ('Y', 'V', '1', '2')) { for (int i = 0; i < height; i++) {
for (int component = 0; component < 3; component++) { memcpy (dstbuf + dststride * i, srcbuf + srcstride * i, srcstride);
// TODO: Get format properly rather than hard-coding it. Use gst_video_* APIs *? }
if (component == 0) { }
srcstride = GST_ROUND_UP_4 (vh->rcSource.right); else if (fourcc == GST_MAKE_FOURCC ('Y', 'V', '1', '2')) {
src = srcbuf; for (int component = 0; component < 3; component++) {
} // TODO: Get format properly rather than hard-coding it. Use gst_video_* APIs *?
else { if (component == 0) {
srcstride = GST_ROUND_UP_4 ( GST_ROUND_UP_2 (vh->rcSource.right) / 2); srcstride = GST_ROUND_UP_4 (vh->rcSource.right);
if (component == 1) src = srcbuf;
src = srcbuf + GST_ROUND_UP_4 (vh->rcSource.right) * GST_ROUND_UP_2 (vh->rcSource.bottom); }
else else {
src = srcbuf + GST_ROUND_UP_4 (vh->rcSource.right) * GST_ROUND_UP_2 (vh->rcSource.bottom) + srcstride = GST_ROUND_UP_4 ( GST_ROUND_UP_2 (vh->rcSource.right) / 2);
srcstride * (GST_ROUND_UP_2 (vh->rcSource.bottom) / 2); if (component == 1)
} src = srcbuf + GST_ROUND_UP_4 (vh->rcSource.right) * GST_ROUND_UP_2 (vh->rcSource.bottom);
else
/* Is there a better way to do this? This is ICK! */ src = srcbuf + GST_ROUND_UP_4 (vh->rcSource.right) * GST_ROUND_UP_2 (vh->rcSource.bottom) +
if (component == 0) { srcstride * (GST_ROUND_UP_2 (vh->rcSource.bottom) / 2);
dststride = width; }
dst = dstbuf;
rows = height; /* Is there a better way to do this? This is ICK! */
} else if (component == 1) { if (component == 0) {
dststride = width / 2; dststride = width;
dst = dstbuf + width * height; dst = dstbuf;
rows = height/2; rows = height;
} } else if (component == 1) {
else { dststride = width / 2;
dststride = width / 2; dst = dstbuf + width * height;
dst = dstbuf + width * height + rows = height/2;
width/2 * height/2; }
rows = height/2; else {
} dststride = width / 2;
dst = dstbuf + width * height +
for (int i = 0; i < rows; i++) { width/2 * height/2;
memcpy (dst + i * dststride, src + i * srcstride, srcstride); rows = height/2;
} }
}
} for (int i = 0; i < rows; i++) {
memcpy (dst + i * dststride, src + i * srcstride, srcstride);
return S_OK; }
} }
}
GstFlowReturn VideoFakeSrcPin::PushBuffer(GstBuffer *buffer) return S_OK;
{ }
IMediaSample *pSample = NULL;
STDMETHODIMP VideoFakeSrcPin::Disconnect ()
byte *data = GST_BUFFER_DATA (buffer); {
GST_DEBUG_OBJECT (this, "Disconnecting pin");
/* TODO: Use more of the arguments here? */ HRESULT hr = CDynamicOutputPin::Disconnect();
HRESULT hres = GetDeliveryBuffer(&pSample, NULL, NULL, 0); GST_DEBUG_OBJECT (this, "Pin disconnected");
if (SUCCEEDED (hres)) return hr;
{ }
BYTE *sample_buffer;
AM_MEDIA_TYPE *mediatype; HRESULT VideoFakeSrcPin::Inactive ()
{
pSample->GetPointer(&sample_buffer); GST_DEBUG_OBJECT (this, "Pin going inactive");
pSample->GetMediaType(&mediatype); HRESULT hr = CDynamicOutputPin::Inactive();
if (mediatype) GST_DEBUG_OBJECT (this, "Pin inactivated");
SetMediaType (mediatype); return hr;
}
if(sample_buffer)
{ HRESULT VideoFakeSrcPin::BreakConnect ()
/* Copy to the destination stride. {
* This is not just a simple memcpy because of the different strides. GST_DEBUG_OBJECT (this, "Breaking connection");
* TODO: optimise for the same-stride case and avoid the copy entirely. HRESULT hr = CDynamicOutputPin::BreakConnect();
*/ GST_DEBUG_OBJECT (this, "Connection broken");
CopyToDestinationBuffer (data, sample_buffer); return hr;
} }
pSample->SetDiscontinuity(FALSE); /* Decoded frame; unimportant */ HRESULT VideoFakeSrcPin::CompleteConnect (IPin *pReceivePin)
pSample->SetSyncPoint(TRUE); /* Decoded frame; always a valid syncpoint */ {
pSample->SetPreroll(FALSE); /* For non-displayed frames. GST_DEBUG_OBJECT (this, "Completing connection");
Not used in GStreamer */ HRESULT hr = CDynamicOutputPin::CompleteConnect(pReceivePin);
GST_DEBUG_OBJECT (this, "Completed connection: %x", hr);
/* Disable synchronising on this sample. We instead let GStreamer handle return hr;
* this at a higher level, inside BaseSink. */ }
pSample->SetTime(NULL, NULL);
STDMETHODIMP VideoFakeSrcPin::Block(DWORD dwBlockFlags, HANDLE hEvent)
hres = Deliver(pSample); {
pSample->Release(); GST_DEBUG_OBJECT (this, "Calling Block()");
HRESULT hr = CDynamicOutputPin::Block (dwBlockFlags, hEvent);
if (SUCCEEDED (hres)) GST_DEBUG_OBJECT (this, "Called Block()");
return GST_FLOW_OK; return hr;
else if (hres == VFW_E_NOT_CONNECTED) }
return GST_FLOW_NOT_LINKED;
else /* When moving the video to a different monitor, directshow stops and restarts the playback pipeline.
return GST_FLOW_ERROR; * Unfortunately, it doesn't properly block pins or do anything special, so we racily just fail
} * at this point.
else { * So, we try multiple times in a loop, hoping that it'll have finished (we get no notifications at all!)
GST_WARNING ("Could not get sample for delivery to sink: %x", hres); * at some point.
return GST_FLOW_ERROR; */
} #define MAX_ATTEMPTS 10
}
GstFlowReturn VideoFakeSrcPin::PushBuffer(GstBuffer *buffer)
STDMETHODIMP VideoFakeSrcPin::Flush () {
{ IMediaSample *pSample = NULL;
DeliverBeginFlush(); byte *data = GST_BUFFER_DATA (buffer);
DeliverEndFlush(); int attempts = 0;
return S_OK; HRESULT hres;
} BYTE *sample_buffer;
AM_MEDIA_TYPE *mediatype;
VideoFakeSrc::VideoFakeSrc() : CBaseFilter("VideoFakeSrc", NULL, &m_critsec, CLSID_VideoFakeSrc)
{ StartUsingOutputPin();
HRESULT hr = S_OK;
m_pOutputPin = new VideoFakeSrcPin ((CSource *)this, &m_critsec, &hr); while (attempts < MAX_ATTEMPTS)
} {
hres = GetDeliveryBuffer(&pSample, NULL, NULL, 0);
int VideoFakeSrc::GetPinCount() if (SUCCEEDED (hres))
{ break;
return 1; attempts++;
} Sleep(100);
}
CBasePin *VideoFakeSrc::GetPin(int n)
{ if (FAILED (hres))
return (CBasePin *)m_pOutputPin; {
} StopUsingOutputPin();
GST_WARNING ("Could not get sample for delivery to sink: %x", hres);
VideoFakeSrcPin *VideoFakeSrc::GetOutputPin() return GST_FLOW_ERROR;
{ }
return m_pOutputPin;
} pSample->GetPointer(&sample_buffer);
pSample->GetMediaType(&mediatype);
if (mediatype)
SetMediaType (mediatype);
if(sample_buffer)
{
/* Copy to the destination stride.
* This is not just a simple memcpy because of the different strides.
* TODO: optimise for the same-stride case and avoid the copy entirely.
*/
CopyToDestinationBuffer (data, sample_buffer);
}
pSample->SetDiscontinuity(FALSE); /* Decoded frame; unimportant */
pSample->SetSyncPoint(TRUE); /* Decoded frame; always a valid syncpoint */
pSample->SetPreroll(FALSE); /* For non-displayed frames.
Not used in GStreamer */
/* Disable synchronising on this sample. We instead let GStreamer handle
* this at a higher level, inside BaseSink. */
pSample->SetTime(NULL, NULL);
while (attempts < MAX_ATTEMPTS)
{
hres = Deliver(pSample);
if (SUCCEEDED (hres))
break;
attempts++;
Sleep(100);
}
pSample->Release();
StopUsingOutputPin();
if (SUCCEEDED (hres))
return GST_FLOW_OK;
else {
GST_WARNING_OBJECT (this, "Failed to deliver sample: %x", hres);
if (hres == VFW_E_NOT_CONNECTED)
return GST_FLOW_NOT_LINKED;
else
return GST_FLOW_ERROR;
}
}
STDMETHODIMP VideoFakeSrcPin::Flush ()
{
DeliverBeginFlush();
DeliverEndFlush();
return S_OK;
}
VideoFakeSrc::VideoFakeSrc() : CBaseFilter("VideoFakeSrc", NULL, &m_critsec, CLSID_VideoFakeSrc),
m_evFilterStoppingEvent(TRUE)
{
HRESULT hr = S_OK;
m_pOutputPin = new VideoFakeSrcPin ((CSource *)this, &m_critsec, &hr);
}
int VideoFakeSrc::GetPinCount()
{
return 1;
}
CBasePin *VideoFakeSrc::GetPin(int n)
{
return (CBasePin *)m_pOutputPin;
}
VideoFakeSrcPin *VideoFakeSrc::GetOutputPin()
{
return m_pOutputPin;
}
STDMETHODIMP VideoFakeSrc::Stop(void)
{
GST_DEBUG_OBJECT (this, "Stop()");
m_evFilterStoppingEvent.Set();
return CBaseFilter::Stop();
}
STDMETHODIMP VideoFakeSrc::Pause(void)
{
GST_DEBUG_OBJECT (this, "Pause()");
m_evFilterStoppingEvent.Reset();
return CBaseFilter::Pause();
}
STDMETHODIMP VideoFakeSrc::Run(REFERENCE_TIME tStart)
{
GST_DEBUG_OBJECT (this, "Run()");
return CBaseFilter::Run(tStart);
}
STDMETHODIMP VideoFakeSrc::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
{
HRESULT hr;
// The filter is joining the filter graph.
if(NULL != pGraph)
{
IGraphConfig* pGraphConfig = NULL;
hr = pGraph->QueryInterface(IID_IGraphConfig, (void**)&pGraphConfig);
if(FAILED(hr))
return hr;
hr = CBaseFilter::JoinFilterGraph(pGraph, pName);
if(FAILED(hr))
{
pGraphConfig->Release();
return hr;
}
m_pOutputPin->SetConfigInfo(pGraphConfig, m_evFilterStoppingEvent);
pGraphConfig->Release();
}
else
{
hr = CBaseFilter::JoinFilterGraph(pGraph, pName);
if(FAILED(hr))
return hr;
m_pOutputPin->SetConfigInfo(NULL, NULL);
}
return S_OK;
}

View File

@ -22,7 +22,7 @@
#include <streams.h> #include <streams.h>
#include <gst/gst.h> #include <gst/gst.h>
class VideoFakeSrcPin : public CBaseOutputPin class VideoFakeSrcPin : public CDynamicOutputPin
{ {
protected: protected:
/* members */ /* members */
@ -41,11 +41,14 @@ public:
virtual HRESULT CheckMediaType(const CMediaType *pmt); virtual HRESULT CheckMediaType(const CMediaType *pmt);
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
virtual HRESULT DecideBufferSize (IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest); virtual HRESULT DecideBufferSize (IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest);
virtual HRESULT BreakConnect();
virtual HRESULT CompleteConnect(IPin *pReceivePin);
virtual HRESULT Inactive();
STDMETHOD (SetMediaType) (AM_MEDIA_TYPE *pmt); STDMETHOD (SetMediaType) (AM_MEDIA_TYPE *pmt);
STDMETHOD (Flush) (); STDMETHOD (Flush) ();
STDMETHODIMP Notify(IBaseFilter * pSender, Quality q); STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);
STDMETHODIMP Disconnect();
STDMETHODIMP Block(DWORD dwBlockFlags, HANDLE hEvent);
}; };
class VideoFakeSrc : public CBaseFilter class VideoFakeSrc : public CBaseFilter
@ -55,6 +58,8 @@ private:
CCritSec m_critsec; CCritSec m_critsec;
VideoFakeSrcPin *m_pOutputPin; VideoFakeSrcPin *m_pOutputPin;
CAMEvent m_evFilterStoppingEvent;
public: public:
/* methods */ /* methods */
VideoFakeSrc (void); VideoFakeSrc (void);
@ -65,6 +70,11 @@ public:
/* Overrides */ /* Overrides */
int GetPinCount(); int GetPinCount();
CBasePin *GetPin(int n); CBasePin *GetPin(int n);
STDMETHODIMP Run(REFERENCE_TIME tStart);
STDMETHODIMP Stop(void);
STDMETHODIMP Pause(void);
STDMETHODIMP JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName);
}; };
#endif /* __DSHOWVIDEOFAKESRC_H__ */ #endif /* __DSHOWVIDEOFAKESRC_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -65,6 +65,8 @@ struct _GstDshowVideoSink
/* The filter graph (DirectShow equivalent to pipeline */ /* The filter graph (DirectShow equivalent to pipeline */
IFilterGraph *filter_graph; IFilterGraph *filter_graph;
IMediaEventEx *filter_media_event;
/* Renderer wrapper (EVR, VMR9, or VMR) and support code */ /* Renderer wrapper (EVR, VMR9, or VMR) and support code */
RendererSupport *renderersupport; RendererSupport *renderersupport;