Search code examples
delphivideowebcamdirectshow

Webcamera supported video formats


I'm trying to get stream video from USB Web-camera in Delphi XE. Found a working example, but I can't figure out how to get all supported video formats (resolution, color depth, etc). This example works well with fixed Mediatype:

 var
  Form1: TForm1;
  IniFile: TIniFile;
  DeviceName: OleVariant;
  PropertyName: IPropertyBag;
  pDevEnum: ICreateDEvEnum;
  pEnum: IEnumMoniker;
  pMoniker: IMoniker;

  MArray1: array of IMoniker; 

  FGraphBuilder: IGraphBuilder;
  FCaptureGraphBuilder: ICaptureGraphBuilder2;
  FMux: IBaseFilter;
  FSink: IFileSinkFilter;
  FMediaControl: IMediaControl;
  FVideoWindow: IVideoWindow;
  FVideoCaptureFilter: IBaseFilter;
  FAudioCaptureFilter: IBaseFilter;
  FVideoRect: TRect;

  FBaseFilter: IBaseFilter;
  FSampleGrabber: ISampleGrabber;
  MediaType: AM_MEDIA_TYPE;


function TForm1.Initializ: HResult;
begin
  Result := CoCreateInstance(CLSID_SystemDeviceEnum, NIL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, pDevEnum);

  if Result <> S_OK then
    EXIT;

  Result := pDevEnum.CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
    pEnum, 0);

  if Result <> S_OK then
    EXIT;

  setlength(MArray1, 0);

  while (S_OK = pEnum.Next(1, pMoniker, Nil)) do
  begin
    setlength(MArray1, length(MArray1) + 1);
    MArray1[length(MArray1) - 1] := pMoniker;
    Result := pMoniker.BindToStorage(NIL, NIL, IPropertyBag, PropertyName);

    if FAILED(Result) then
      Continue;

    Result := PropertyName.Read('FriendlyName', DeviceName, NIL);

    if FAILED(Result) then
      Continue;

    ListBox1.Items.Add(DeviceName);
  end;

  if ListBox1.Count = 0 then
  begin
    ShowMessage('Webcam not found!');
    Result := E_FAIL;
    EXIT;
  end;
  ListBox1.ItemIndex := 0;

  Result := S_OK;
end;

function TForm1.CreateGraph: HResult;
var
  pConfigMux: IConfigAviMux;

begin
  FVideoCaptureFilter := NIL;
  FVideoWindow := NIL;
  FMediaControl := NIL;
  FSampleGrabber := NIL;
  FBaseFilter := NIL;
  FCaptureGraphBuilder := NIL;
  FGraphBuilder := NIL;

  Result := CoCreateInstance(CLSID_FilterGraph, NIL, CLSCTX_INPROC_SERVER,
    IID_IGraphBuilder, FGraphBuilder);
  if FAILED(Result) then
    EXIT;

  Result := CoCreateInstance(CLSID_SampleGrabber, NIL, CLSCTX_INPROC_SERVER,
    IID_IBaseFilter, FBaseFilter);
  if FAILED(Result) then
    EXIT;

  Result := CoCreateInstance(CLSID_CaptureGraphBuilder2, NIL,
    CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2, FCaptureGraphBuilder);
  if FAILED(Result) then
    EXIT;

  Result := FGraphBuilder.AddFilter(FBaseFilter, 'GRABBER');
  if FAILED(Result) then
    EXIT;

  Result := FBaseFilter.QueryInterface(IID_ISampleGrabber, FSampleGrabber);
  if FAILED(Result) then
    EXIT;

  if FSampleGrabber <> NIL then
  begin

    ZeroMemory(@MediaType, sizeof(AM_MEDIA_TYPE));

    with MediaType do
    begin
      majortype := MEDIATYPE_Video;
      subtype := MEDIASUBTYPE_RGB24;
      formattype := FORMAT_VideoInfo;
    end;

    FSampleGrabber.SetMediaType(MediaType);

    FSampleGrabber.SetBufferSamples(TRUE);

    FSampleGrabber.SetOneShot(FALSE);
  end;

  Result := FCaptureGraphBuilder.SetFiltergraph(FGraphBuilder);
  if FAILED(Result) then
    EXIT;

  if ListBox1.ItemIndex >= 0 then
  begin
    MArray1[ListBox1.ItemIndex].BindToObject(NIL, NIL, IID_IBaseFilter,
      FVideoCaptureFilter);
    FGraphBuilder.AddFilter(FVideoCaptureFilter, 'VideoCaptureFilter');
  end;

  Result := FCaptureGraphBuilder.RenderStream(@PIN_CATEGORY_PREVIEW, nil,
    FVideoCaptureFilter, FBaseFilter, nil);
  if FAILED(Result) then
    EXIT;

  Result := FGraphBuilder.QueryInterface(IID_IVideoWindow, FVideoWindow);
  if FAILED(Result) then
    EXIT;

  FVideoWindow.put_WindowStyle(WS_CHILD or WS_CLIPSIBLINGS);
  FVideoWindow.put_Owner(Panel1.Handle);
  FVideoRect := Panel1.ClientRect;
  FVideoWindow.SetWindowPosition(FVideoRect.Left, FVideoRect.Top,
  FVideoRect.Right - FVideoRect.Left, FVideoRect.Bottom - FVideoRect.Top);
  FVideoWindow.put_Visible(TRUE);

  Result := FGraphBuilder.QueryInterface(IID_IMediaControl, FMediaControl);
  if FAILED(Result) then
    EXIT;
  FMediaControl.Run();
end;

How can I get all webcam supported video formats to combobox? If I need something to add, please, post in comment, thanks.


Solution

  • The code snippet provided is not quite relevant and presumably is just what you have at the moment. To enumerate video formats you typically obtain an output pin of interest first, which you don't do in your code snippet and rely on RenderStream call to do dirty work for you.

    Then, you obtain IAMStreamConfig interface pointer from the pin and enumerate the media types (formats). Alternatively you can enumerate using IPin::EnumMediaTypes, however IAMStreamConfig::GetStreamCaps is the canonical way, esp. for webcams.

    Bonus code here:

    // The TVideoSample class provides access to WebCams and similar Video-capture
    //  devices via DirectShow.
    
    ...
    
    // Fills "FormatArr" with list of all supported video formats (resolution, compression etc...)
    FUNCTION TVideoSample.LoadListOfResolution: HResult;
    ...