I am attempting to make my Panasonic Network camera capturable via MSN,
Skype, AMCap, etc.. Out of the box, these cameras don't support this
function. All the software is completely proprietary. (I purchased this
camera to be a baby monitor for my new baby girl who is today 11 days old)..
The camera works great, but all the software is proprietary. An activex
control lets me listen, view and control the camera in IE. It also comes
with a proprietary audio/video capture program that runs on windows which
does the same.. I however, want to be able to get this data into a WMV
stream so I can use windows media encoder to send video and audio of her to
my PDA...
My understanding is that I'll have to basically do three things.
1) Receive the IP data (MJPEG) and render the frames, one by one into
JPEG, perhaps BMP and feed them into a directshow filter.
2) Register this filter in Windows as a capture filter and implement any
needed methods to setup/control the filter. e.g. specify IP address, change
res, pan/tilt/etc..
3) Figure out what to do with the audio..
I'm working on part two now, as I believe it will be more difficult than
part 1.
To learn how to do Part 1, I've decided to modify a filter that I already
know works. I am using a sample from CodeProject which is titled
"DirectShow source filter for painting on DC".
http://www.codeproject.com/KB/directx/Paint_your_source_filter.aspx I know
this filter works because I've used GraphEditPlus available from
http://www.thedeemon.com/ to render this directshow filter.
I've figured out how to modify this source code to implement
register/unregistering this filter as a capturable filter using
DllRegisterServer/DllUnRegisterServer. However at this point, when I try to
use it in AMCap, I get the following run-time error:
-------
Error 80004002: Cannot find VCapture:IAMStreamConfig
-------
My interpretation of this error is that I simply need to implement the
IAMStreamConfig interface, and the interface is clearly defined here:
http://msdn2.microsoft.com/en-us/library/ms784115(VS.85).aspx
Unfortunately, my stumbling block here is that I just don't know how to go
about implementing an interface in C++. I've been reading about using
interfaces in C++ and I find some articles that use compiler macros to allow
C++ to support interfaces, other articles saying Visual Studio has this
built in ..
Does anyone suggest any books, blogs, articles that might help me to
understand how to implement this interface? I'm really lost at the moment
and really want to accomplish this.
Thanks in advance for everyone's help.
Sincerely,
Robert C. Wafle
Proud new Father
> things. 1) Receive the IP data (MJPEG) and render the
> frames, one by one into JPEG, perhaps BMP and feed them
> into a directshow filter.
If you want your push source to work in WME9, you need to
output uncompressed RGB or YUV. To decompress the MJPEG
stream, you can create a DirectShow graph inside your push
source that ends in a SampleGrabber configured to only
accept the uncompressed video subtype you want to support.
> 2) Register this filter in Windows as a capture filter
> and implement any needed methods to setup/control the
> filter. e.g. specify IP address, change res,
> pan/tilt/etc..
To work as a capture filter, you need to implement a few
additional things:
http://msdn2.microsoft.com/en-us/library/ms788161(VS.85).aspx
> 3) Figure out what to do with the audio..
A push source can have multiple output pins, including
audio.
> Unfortunately, my stumbling block here is that I just
> don't know how to go about implementing an interface in
> C++. I've been reading about using interfaces in C++ and
> I find some articles that use compiler macros to allow
> C++ to support interfaces, other articles saying Visual
> Studio has this built in ..
Interface is the COM word that in C++ simply means pure
virtual class, that is a normal class that only has pure
virtual methods. So, to implement the interface, simply
inherit it in your class and override all of its methods,
including the ones defined in its ancestors (if any and not
already implemented by the base class you are using). Notice
that in COM all interfaces ultimately inherit from IUnknown,
but the IUnknown methods will be already implemented by the
base class you are using, so you don't need to. But you will
need to modify your base class' QueryInterface() (or
NonDelegatingQueryInterface() if you are using the
BaseClasses library) to return a reference to your
implementation when queried for the added interface.
The EZRGB24 sample demonstrates how to implement a custom
interface on the filter. Implementing an interface (custom
or otherwise) on the pin works the same way.
--
// Alessandro Angeli
// MVP :: DirectShow / MediaFoundation
// mvpnews at riseoftheants dot com
// http://www.riseoftheants.com/mmx/faq.htm
Thank you very much for your reply.
After reading your reply and your reference to QueryInterface I did some
more reading. I realize that I'm lacking basic skills working with COM
Interfaces, and that making my class implement more functionality via
interface in C++ is NOT even close to what I need. I need to implement
QueryInterface, and there appears to be lots of documentation out there how
to do this..
Thanks for pointing me back in the right direction. I will rest much better
tonight. I've always needed an excuse to learn some basic COM programming
skills. :)
Rob
"Alessandro Angeli" <nob...@nowhere.in.the.net> wrote in message
news:#4kXPPyp...@TK2MSFTNGP06.phx.gbl...
> After reading your reply and your reference to
> QueryInterface I did some more reading. I realize that
> I'm lacking basic skills working with COM Interfaces, and
> that making my class implement more functionality via
> interface in C++ is NOT even close to what I need. I
> need to implement QueryInterface, and there appears to be
> lots of documentation out there how to do this..
If you are using the DirectShow BaseClasses, you don't need
to worry about COM too much, since the BaseClasses take care
of that for you, and you should not override
QueryInterface() directly but only
NonDelegatingQueryInterface():
http://msdn2.microsoft.com/en-us/library/ms783086(VS.85).aspx
> Thanks for pointing me back in the right direction. I
> will rest much better tonight. I've always needed an
> excuse to learn some basic COM programming skills. :)
If you really want to learn the basics of COM, here is your
starting point:
http://msdn2.microsoft.com/en-us/library/ms694363%28VS.85%29.aspx
http://msdn2.microsoft.com/en-us/library/ms686565%28VS.85%29.aspx
http://msdn2.microsoft.com/en-us/library/ms809982.aspx
http://msdn2.microsoft.com/en-us/library/ms809983.aspx
Notice however that DirectShow makes a very light use of
COM, so that you don't need to know much more than what
IUnknown is.
Thanks again for your help! I sure was lost. I found other people with the
same error trying to do this too, but no responses to the threads showing
what exactly solved their problem, so I am posting how I got to "here" from
"way out there".. And, trust me I really feel like I was "way out
somewhere" on this one..
You said:
> If you are using the DirectShow BaseClasses, you don't need to worry about
> COM too much, since the BaseClasses take care of that for you, and you
> should not override QueryInterface() directly but only
> NonDelegatingQueryInterface():
Thanks for mentioning using NonDelegatingQueryInterface.. This was a big
hint for me. The example I'm trying to modify does indeed use the base
classes, so I will probably need to do so. And, if using the base classes
and just knowing that IUnknown exists is enough, I'll be patient with my
COM skills.
So.. I was looking through the base classes trying to comprehend what is
going on ... and CBasePin caught my eye, because it is using the exact
syntax I tried to use:
Line 330 of amfilter.h:
class AM_NOVTABLE CBasePin : public CUnknown, public IPin, public
IQualityControl
Which to me seems to inherit from CUnknown, but implements IPin and
IQualityControl...
http://msdn2.microsoft.com/en-us/library/ms786513(VS.85).aspx
I also noticed in the EZRGB24 sample on line 10 of ezrgb.h, the same syntax
is used for CEZrgb24:
class CEZrgb24 : public CTransformFilter,
public IIPEffect,
public ISpecifyPropertyPages,
public CPersistStream
{ ... }
So.. I thought to myself... Well darn, that's what I tried to do but I
couldn't get my code to compile at all.
When I tried to use the above syntax in my code like this:
class CSnakeStream : public CSourceStream, public IAMStreamConfig
{ ... }
I would get the following error:
---
Error 1 error C2259: 'CSnakeStream' : cannot instantiate abstract classc:\users\public\downloads\snakesourcefilter\snakesourcefilter2\fsnake.cpp 30---
And, I expected an error at this point, but was kind of hoping it would say
"Hey you, you doornail! You forgot to implement the following methods which
implement the IAMStreamConfig interface (GetFormat, GetNumberOfCapabilities,
GetStreamCaps and SetFormat)" .. which I am assuming the above error really
means..
I wasn't quite sure so I kept looking at the samples, hoping more would jump
out at me.. sure enough it did:
I noticed similar code in amfilter.h and ezrbg.h... both headers had :
DECLARE_IUNKNOWN // which is a compiler macro
and then the methods for the interfaces are mostly implemented with:
STDMETHODIMP // also a compiler macro
For example, lines 411 - 433 of amfilter.h read:
DECLARE_IUNKNOWN
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void
** ppv);
STDMETHODIMP_(ULONG) NonDelegatingRelease();
STDMETHODIMP_(ULONG) NonDelegatingAddRef();
// --- IPin methods ---
// take lead role in establishing a connection. Media type pointer
// may be null, or may point to partially-specified mediatype
// (subtype or format type may be GUID_NULL).
STDMETHODIMP Connect(
IPin * pReceivePin,
__in_opt const AM_MEDIA_TYPE *pmt // optional media type
);
// (passive) accept a connection from another pin
STDMETHODIMP ReceiveConnection(
IPin * pConnector, // this is the initiating connecting pin
const AM_MEDIA_TYPE *pmt // this is the media type we will
exchange
);
STDMETHODIMP Disconnect();
and lines 18-46 of ezrgb24.h read:
DECLARE_IUNKNOWN;
static CUnknown * WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);
// Reveals IEZrgb24 and ISpecifyPropertyPages
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void ** ppv);
// CPersistStream stuff
HRESULT ScribbleToStream(IStream *pStream);
HRESULT ReadFromStream(IStream *pStream);
// Overrriden from CTransformFilter base class
HRESULT Transform(IMediaSample *pIn, IMediaSample *pOut);
HRESULT CheckInputType(const CMediaType *mtIn);
HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut);
HRESULT DecideBufferSize(IMemAllocator *pAlloc,
ALLOCATOR_PROPERTIES *pProperties);
HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
// These implement the custom IIPEffect interface
STDMETHODIMP get_IPEffect(int *IPEffect, REFTIME *StartTime, REFTIME
*Length);
STDMETHODIMP put_IPEffect(int IPEffect, REFTIME StartTime, REFTIME
Length);
// ISpecifyPropertyPages interface
STDMETHODIMP GetPages(CAUUID *pPages);
// CPersistStream override
STDMETHODIMP GetClassID(CLSID *pClsid);
Which lead me to believe that I may need to use these macros when I
implement my interfaces..
And, after much stumbling around, I tried the following code in the
CSnakeStream class in my header as public methods:
STDMETHODIMP GetFormat(
AM_MEDIA_TYPE **pmt
);
STDMETHODIMP GetNumberOfCapabilities(
int *piCount,
int *piSize
);
STDMETHODIMP GetStreamCaps(
int iIndex,
AM_MEDIA_TYPE **pmt,
BYTE *pSCC
);
STDMETHODIMP SetFormat(
AM_MEDIA_TYPE *pmt
);
And, then in my .cpp file, I stubbed out the following methods:
STDMETHODIMP CSnakeFilter::GetFormat(
AM_MEDIA_TYPE **pmt
)
{
return E_NOTIMPL; // not implemented
}
STDMETHODIMP CSnakeFilter::GetNumberOfCapabilities(
int *piCount,
int *piSize
)
{
return E_NOTIMPL; // not implemented
}
STDMETHODIMP CSnakeFilter::GetStreamCaps(
int iIndex,
AM_MEDIA_TYPE **pmt,
BYTE *pSCC
)
{
return E_NOTIMPL; // not implemented
}
STDMETHODIMP CSnakeFilter::SetFormat(
AM_MEDIA_TYPE *pmt
)
{
return E_NOTIMPL; // not implemented
}
And, I also modified NonDelegatingQueryInterface.
And, wouldn't you know it... It compiled!!! (Perhaps, I was indeed needing
to implement these methods).. Hurray!! (or so I thought)
And, I got the same error... I thought to myself "huh?..." and then a
hunch came to me.. Perhaps, I implemented the IAMStreamConfig interface on
CSnakeStream, when I was supposed to implement it on CSnakeFilter... worth a
shot.. I thought..
So, I moved all my code to the appropriate files, which actually made a
whole lot of sense because my implementation of NonDelegatingQueryInterface
seems to make more sense in this case (as it queries the base class if no
matching IIDs are found in my class)
STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv)
{
CheckPointer(ppv,E_POINTER);
if (riid == IID_IAMStreamConfig) {
return GetInterface((IAMStreamConfig *) this, ppv);
} else {
return CSource::NonDelegatingQueryInterface(riid, ppv);
}
}
And I tried again.
Sure enough, I have a new application error from AMCap ("This graph cannot
be previewed!")
Which, also sounds like an error I would expect at this point, and program
flow of AMCap is identical to my Logitech Quickcam so I suspect I've not
broken anything at this point..
I believe I am finally to the point where I can do the "few additional
things" you mentioned which at this point I believe are:
Create my preview pin
Create my capture pin
Be sure they both expose the IKsPropertySet interface.
> To work as a capture filter, you need to implement a few additional
> things:
>
> http://msdn2.microsoft.com/en-us/library/ms788161(VS.85).aspx
I think its time for a nap, or perhaps some coffee.
Could you confirm that my implementation of NonDelegatingQueryInterface
implementation looks correct? (I think it is, but I could have missed
something)...
I feel like I am starting to get the hang of this.
Wish me luck!
Thanks
Rob
> When I tried to use the above syntax in my code like this:
> class CSnakeStream : public CSourceStream, public
> IAMStreamConfig { ... }
>
> I would get the following error:
>
> ---
> Error 1 error C2259: 'CSnakeStream' : cannot instantiate
> abstract
> classc:\users\public\downloads\snakesourcefilter\snakesourcefilter2\fsnake.cpp
> 30---
> And, I expected an error at this point, but was kind of
> hoping it would say "Hey you, you doornail! You forgot
> to implement the following methods which implement the
> IAMStreamConfig interface (GetFormat,
> GetNumberOfCapabilities, GetStreamCaps and SetFormat)" ..
> which I am assuming the
> above error really means..
In C++, an interface is just a purely abstract class (that
is, a class that contains only purely virtual methods) so
inheriting such a class creates an abstract class unless you
actually override all of the purely virtual methods. IIRC,
the output windows of the compiler will tell you what method
implementations are missing.
> I wasn't quite sure so I kept looking at the samples,
> hoping more would jump out at me.. sure enough it did:
>
> I noticed similar code in amfilter.h and ezrbg.h... both
> headers had :
> DECLARE_IUNKNOWN // which is a compiler macro
>
> and then the methods for the interfaces are mostly
> implemented with:
> STDMETHODIMP // also a compiler macro
That's just a macro for "HRESULT STDMETHODCALLAPI", which is
not really important. It's the DECLARE_IUNKNOWN which is
important, since it contains the implementation for the
IUnknown methods necessary in the BaseClasses if you
implement an additional interface.
> And, I got the same error... I thought to myself
> "huh?..." and then a hunch came to me.. Perhaps, I
> implemented the
> IAMStreamConfig interface on CSnakeStream, when I was
> supposed to implement it on
> CSnakeFilter... worth a shot.. I thought..
No, the docs tell you explicitly that IAMStreamConfig must
be implemented on the output pins, not the filter.
> Could you confirm that my implementation of
> NonDelegatingQueryInterface implementation looks correct?
> (I think it is, but I could
> have missed something)...
It is, but it needs to be moved to the pins, otherwise it is
useless. Also, IAMStreamConfig is optional and what you
really need is IKsPropertySet so that the application can
discover the pin categories: you need exactly 1
PIN_CATEGORY_CAPTURE, 0 or 1 PIN_CATEGORY_PREVIEW and 0 or
more pins that are neither.