Why is embedded laptop webcam not firing NewFrameEvent using AForge or DirectShow

  aforge, c++, directshow

I have an embedded webcam on my laptop. I have another USB webcam. This USB webcam works well both with AForge in C# and DirectShow in C++. I would like to write applications using both of these frameworks.

The problem is that my embedded webcam doesn’t fire the NewFrameEvent on AForge. With DirectShow it creates an empty AVI file with only the header.

Here is the code for DirectShow:

#include <iostream>
#include <windows.h>
#include <initguid.h>
#include <dshow.h>

int main()
{
    HRESULT hr = CoInitialize(NULL);
    
    //Initialise device enumerator
    IEnumMoniker *device_enumerator;
    ICreateDevEnum *dev_enum;
    hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&dev_enum));
    hr = dev_enum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &device_enumerator, 0);
    dev_enum->Release();
    
    //Bind moniker to device
    IMoniker *moniker = NULL;
    while (device_enumerator->Next(1, &moniker, NULL) == S_OK)
    {
        
    }
    
    //Build a graph and add a capture filter to it
    IGraphBuilder *graph = NULL;
    ICaptureGraphBuilder2 *build = NULL;
    hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, 
        CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, (void**)&build);
    hr = CoCreateInstance(CLSID_FilterGraph, 0, CLSCTX_INPROC_SERVER,
            IID_IGraphBuilder, (void**)&graph);
    build->SetFiltergraph(graph);
    IBaseFilter *cap = NULL;
    hr = moniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&cap);
    hr = graph->AddFilter(cap, L"Capture Filter");
    
    //Set output file (connect cap filter to avi mux)
    IBaseFilter *mux;
    hr = build->SetOutputFileName(&MEDIASUBTYPE_Avi, L"C:usersuserdocumentswebcamtestvideo.avi", &mux, NULL);
    hr = build->RenderStream(&PIN_CATEGORY_CAPTURE, &MEDIATYPE_Video, 
    cap, NULL, mux);
    
    mux->Release();
    
    //Start recording
    IMediaControl *control;
    hr = graph->QueryInterface(IID_IMediaControl, (void**)&control);
    
    hr = control->Run();

    std::cin.get();
    
    hr = control->Stop();
    
    CoUninitialize();
    
    return 0;
}

I compile this code using g++ c:usersuserdocumentswebcamtestdirectshow.cpp -lole32 -loleaut32 -oc:usersuserdocumentswebcamtestdirectshow.exe

The code for C# and AForge:

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using AForge.Video;
using AForge.Video.DirectShow;

namespace Webcam
{
    public partial class MainWindow : Window
    {
        VideoCaptureDevice device = null;
        FilterInfoCollection VideoCaptureDevices;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void Start_Click(object sender, RoutedEventArgs e)
        {
            VideoCaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            device = new VideoCaptureDevice(VideoCaptureDevices[0].MonikerString);
            device.NewFrame += NewFrame;
            device.Start();
        }

        private void NewFrame(object sender, NewFrameEventArgs e)
        {
            Debug.WriteLine("Hello");
            Bitmap bmp = e.Frame;
            var handle = bmp.GetHbitmap();
            BitmapSource image = Imaging.CreateBitmapSourceFromHBitmap(handle, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            image.Freeze();
            Video.Dispatcher.Invoke(new Action(() => Video.Source = image));
        }

        private void Stop_Click(object sender, RoutedEventArgs e)
        {
            device.SignalToStop();
        }
    }
}

MainWindow.xaml

<Window x:Class="Webcam.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Webcam"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="5*"/>
            <ColumnDefinition Width="20*"/>
            <ColumnDefinition Width="5*"/>
        </Grid.ColumnDefinitions>
        <Button Name="Start" Grid.Column="0" Click="Start_Click"/>
        <Image Name="Video" Grid.Column="1"/>
        <Button Name="Stop" Grid.Column="2" Click="Stop_Click"/>
    </Grid>
</Window>

The embedded laptop webcam seems to start since there is a light indicator on it and it turns on. In AForge it doesn’t fire the NewFrameEvent and on DirectShow it creates an empty AVI file. This same webcam works with the Windows camera app.

What do you think is the problem with my code/webcam?

Is there a way for it to work with my embedded laptop webcam?

I feel like the events are related and the camera could not be compatible with DirectShow. Since AForge is a wrapper around DirectShow if it doesn’t work it could be related.

Source: Windows Questions C++

LEAVE A COMMENT