I've been working on an application that uses Directshow.NET, and decided to start tinkering with GraphEd.exe to figure out the exact route I need to take.

The simplest version of what I want is in the image above (where "test.mpeg" is a "File writer" filter).
Sure enough, what looks easy in GraphEd is not as simple as coding it. After a few seconds, I realized that directshow is something I just don't understand. Here is my C# code attempt:
int hr;
IBaseFilter cameraStream = null;
IBaseFilter mpegEncoder = null;
IBaseFilter fileWriter = null;
ICaptureGraphBuilder2 capGraph = null;
filterGraph = (IFilterGraph2)new FilterGraph();
try
{
    capGraph = (ICaptureGraphBuilder2)new CaptureGraphBuilder2();
    hr = capGraph.SetFiltergraph(filterGraph);
    Marshal.ThrowExceptionForHR(hr);
    hr = filterGraph.AddSourceFilterForMoniker(dev.Mon, null, dev.Name, out cameraStream);
    Marshal.ThrowExceptionForHR(hr);
    IPin cameraData = null;
    hr = capGraph.FindPin(cameraStream, PinDirection.Output, PinCategory.Capture, MediaType.Video, true, 0, out cameraData );
    //hr = cameraStream.FindPin("Capture", out cameraData);
    Marshal.ThrowExceptionForHR(hr);
    mpegEncoder = (IBaseFilter)new MJPGEnc();
    hr = filterGraph.AddFilter(mpegEncoder, "mpeg encoder");
    //hr = filterGraph.FindFilterByName("Microsoft MPEG-2 Video Encoder", out mpegEncoder);
    Marshal.ThrowExceptionForHR(hr);
    IPin mpegInput = null;
    //hr = mpegEncoder.FindPin("Input0", out mpegInput);
    hr = capGraph.FindPin(mpegEncoder, PinDirection.Input, null, null, true, 0, out mpegInput);
    Marshal.ThrowExceptionForHR(hr);
    filterGraph.Connect(cameraData, mpegInput);
    IPin mpegOutput = null;
    //hr = mpegEncoder.FindPin("Output", out mpegOutput);
    hr = capGraph.FindPin(mpegEncoder, PinDirection.Output, null, null, true, 0, out mpegOutput);
    Marshal.ThrowExceptionForHR(hr);
    //hr = filterGraph.FindFilterByName("File writer", out fileWriter);
    fileWriter = (IBaseFilter)new FileWriter();
    IFileSinkFilter test = fileWriter as IFileSinkFilter2;
    AMMediaType mtype = new AMMediaType();
    mtype.majorType = MediaType.Video;
    mtype.subType = MediaSubType.RGB24;
    mtype.formatPtr = IntPtr.Zero;
    test.SetFileName(videoPath, mtype );
    IPin fwriterIn = null;
    //hr = fileWriter.FindPin("in", out fwriterIn);
    hr = capGraph.FindPin(fileWriter, PinDirection.Input, null, null, true, 0, out fwriterIn);
    Marshal.ThrowExceptionForHR(hr);
    filterGraph.Connect(mpegOutput, fwriterIn);
    hr = capGraph.RenderStream(null, null, cameraStream, null, fileWriter); // *** Breaks on this line! ***
    Marshal.ThrowExceptionForHR(hr);
    mediaControl = filterGraph as IMediaControl;
}
finally
{
    if (cameraStream != null)
    {
        Marshal.ReleaseComObject(cameraStream);
        cameraStream = null;
    }
    if (mpegEncoder != null)
    {
        Marshal.ReleaseComObject(mpegEncoder);
        mpegEncoder = null;
    }
    if (fileWriter != null)
    {
        Marshal.ReleaseComObject(fileWriter);
        fileWriter = null;
    }
    if (capGraph != null)
    {
        Marshal.ReleaseComObject(capGraph);
        capGraph = null;
    }
}
After writing and looking at how ridiculous my code was (as far as programming logic is concerned), I realized I needed some help.
Could anyone please direct me to some sort of structured directshow tutorial that explains things to me as if I'm a huge newbie, or possibly link me to some sort of C# library that handles webcam to file recording? I'm not generally a win32 programmer, so anything that eases the pain should be good :)
Also, I do have camera device enumeration code that seems to work:
private void rescan_camera()
{
    comboBox1.Items.Clear();
    DsDevice[] cameraDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
    for(int i=0; i < cameraDevices.Length; i++) {
        comboBox1.Items.Add(cameraDevices[i].Name);
    }
    if (comboBox1.Items.Count > 0) comboBox1.SelectedIndex = 0;
}
I can get the moniker data from a DsDevice, which I know is a key part to telling the directshow filter graph where I want to record from, but that's about the extent of my knowledge.
Edit: Updated code, shows exact place of line break.