I have a web cam that's capable of running both YUY and MJPG color spaces. This camera default is YUY, what do i need to alter or add in my DirectShow graph to start the camera in MJPG programmatically? My code is very similar to the typical graph setup, resembling the DxSnap example found in the DirectShow.Net sample directory. documentation is scarce regarding this, the only sample i've seen is displaying the capture pin property page and changing it through that UI, however my technique needs to be implemented programmatically. any help, guidance or advice would be greatly appreciated. Thank you
Here is my graph construction:
/// <summary> build the capture graph for grabber. </summary>
private void SetupGraph(DsDevice dev, int iFrameRate, int iWidth, int iHeight)
{
int hr;
ISampleGrabber sampGrabber = null;
ICaptureGraphBuilder2 capGraph = null;
// Get the graphbuilder object
m_graphBuilder = (IFilterGraph2)new FilterGraph();
m_mediaCtrl = m_graphBuilder as IMediaControl;
try
{
// Get the ICaptureGraphBuilder2
capGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
// Get the SampleGrabber interface
sampGrabber = (ISampleGrabber)new SampleGrabber();
// Start building the graph
hr = capGraph.SetFiltergraph(m_graphBuilder);
DsError.ThrowExceptionForHR(hr);
// Add the video device
hr = m_graphBuilder.AddSourceFilterForMoniker(dev.Mon, null, "Video input", out capFilter);
DsError.ThrowExceptionForHR(hr);
IBaseFilter baseGrabFlt = (IBaseFilter)sampGrabber;
ConfigureSampleGrabber(sampGrabber);
// Add the frame grabber to the graph
hr = m_graphBuilder.AddFilter(baseGrabFlt, "Ds.NET Grabber");
DsError.ThrowExceptionForHR(hr);
// Get list of video compressors on the system
DsDevice[] videoCompressors = DsDevice.GetDevicesOfCat(FilterCategory.VideoCompressorCategory);
IBaseFilter videoCompressorFilter = null;
string videoCompressor = "MJPEG Compressor";
foreach (DsDevice compressor in videoCompressors)
{
if (compressor.Name == videoCompressor)
{
object obj = null;
Guid bfGuid = typeof(IBaseFilter).GUID;
compressor.Mon.BindToObject(null, null, ref bfGuid, out obj);
videoCompressorFilter = obj as IBaseFilter;
break; // Found the compressor - stop looking for it
}
}
if (videoCompressorFilter != null)
{
hr = m_graphBuilder.AddFilter(videoCompressorFilter, videoCompressor);
DsError.ThrowExceptionForHR(hr);
}
// If any of the default config items are set
if (iFrameRate + iHeight + iWidth > 0)
{
SetConfigParms(capGraph, capFilter, iFrameRate, iWidth, iHeight);
}
hr = capGraph.RenderStream(PinCategory.Capture, MediaType.Video, capFilter, null, baseGrabFlt);
DsError.ThrowExceptionForHR(hr);
SaveSizeInfo(sampGrabber);
}
finally
{
if (sampGrabber != null)
{
Marshal.ReleaseComObject(sampGrabber);
sampGrabber = null;
}
if (capGraph != null)
{
Marshal.ReleaseComObject(capGraph);
capGraph = null;
}
}
}
private void SaveSizeInfo(ISampleGrabber sampGrabber)
{
int hr;
// Get the media type from the SampleGrabber
AMMediaType media = new AMMediaType();
hr = sampGrabber.GetConnectedMediaType(media);
DsError.ThrowExceptionForHR(hr);
if ((media.formatType != FormatType.VideoInfo) || (media.formatPtr == IntPtr.Zero))
{
throw new NotSupportedException("Unknown ISampleGrabber Media Format");
}
// Grab the size info
VideoInfoHeader videoInfoHeader = (VideoInfoHeader)Marshal.PtrToStructure(media.formatPtr, typeof(VideoInfoHeader));
m_videoWidth = videoInfoHeader.BmiHeader.Width;
m_videoHeight = videoInfoHeader.BmiHeader.Height;
m_stride = m_videoWidth * (videoInfoHeader.BmiHeader.BitCount / 8);
DsUtils.FreeAMMediaType(media);
media = null;
}
private void ConfigureSampleGrabber(ISampleGrabber sampGrabber)
{
AMMediaType media;
int hr;
// Set the media type to Video/RBG24
media = new AMMediaType();
media.majorType = MediaType.Video;
media.subType = MediaSubType.MJPG;
media.formatType = FormatType.VideoInfo;
hr = sampGrabber.SetMediaType(media);
DsError.ThrowExceptionForHR(hr);
DsUtils.FreeAMMediaType(media);
media = null;
// Configure the samplegrabber
hr = sampGrabber.SetCallback(this, 1);
DsError.ThrowExceptionForHR(hr);
}
function for frame callback:
void OnFrameDone()
{
try
{
int w = Width;
int h = Height;
if (((w < 32) || (h < 32)))
{
return;
}
int stride = w * 3;
lock (this)
{
GCHandle handle = GCHandle.Alloc(savedArray, GCHandleType.Pinned);
int scan0 = (int)handle.AddrOfPinnedObject();
scan0 += (h - 1) * stride;
Bitmap b = new Bitmap(w, h, -stride, PixelFormat.Format24bppRgb, (IntPtr)scan0);
//switch (FrameDirection)
//{
// case VideoDir.Portrait:
// b.RotateFlip(RotateFlipType.Rotate90FlipNone);
// break;
// case VideoDir.Landscape:
// b.RotateFlip(RotateFlipType.Rotate180FlipNone);
// b.RotateFlip(RotateFlipType.Rotate180FlipNone);
// break;
//}
if(FrameCaptureComplete != null)
FrameCaptureComplete(b);
handle.Free();
}
}
catch (Exception ex)
{
string error = ex.Message;
}
return;
}
Throughout all this trial and error, my research reaches a conclusion that my efforts were not exactly failed attempts. The Microsoft MJPEG Decompressor is not working above 3MP resolution, i was attempting to run the graph at 5MP. Using a 3rd party MJPEG Compressor that was capable of running 5MP fixed all the issues i was experiencing.
Thank you Roman for your help.