Announcement

Collapse
No announcement yet.

DirectShow SampleGrabber

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • DirectShow SampleGrabber

    Using DirectShow, I hope to capture and modify video frames before they are displayed on the monitor.

    This will be one of those threads where I start with failing code and hopefully show progress towards the goal.

    And as always, comments/suggestions on the code are appreciated.

    The code below successfully displays the first camera it finds. The function FrameGrabber is then intended to capture a single frame, making it available for modifying, but the function fails to compile - so far because I'm not setting the pVIH variable correctly.

    I'm guessing also that I'm not using the pBuffer correctly And finally, I'm not sure what structure pBuffer will point to - a BITMAP or just an array of byte data. Beyond that, the code below only grabs a single frame, whereas I'll want to continuously grab/modify/return frames.

    I'm still reading the documentation and experimenting with the code ...

    Code:
    'Compilable Example:
    #Compile Exe
    #Dim All
    
    #Debug Error On
    #Debug Display On
    
    %Unicode = 1
    #Include "Win32API.inc"
    #Include Once "dshow.inc"
    #Include "qedit.inc"
    
    %WM_GraphNotify = %WM_User + 13
    %IDC_Button = 500
    
    Global hDlg, wRes, hRes  As Dword
    Global pBuffer As String Ptr, pBufferSize As Long
    
    Global pGraph          As IGraphBuilder           'Filter Graph Manager
    Global pBuild          As ICaptureGraphBuilder2   'Capture Graph Builder
    Global pSysDevEnum     As ICreateDevEnum          'enumeration object
    Global pEnumCat        As IEnumMoniker
    Global pMoniker        As IMoniker                'contains information about other objects
    Global pceltFetched    As Dword
    Global pCap            As IBaseFilter             'Video capture filter
    Global pControl        As IMediaControl
    Global pWindow         As IVideoWindow            'Display Window
    Global pConfig         As IAMStreamConfig   'video output format
    
    Global pGrabber        As ISampleGrabber
    Global pSample         As IMediaSample
    Global pEvents         As IMediaEventEX
    
    Function PBMain() As Long
       Dialog Default Font "Tahoma", 12, 1
       Dialog New Pixels, 0, "DirectShow SampleGrabber Test",300,300,640+150,480, %WS_OverlappedWindow Or %WS_ClipSiblings Or %WS_ClipChildren To hDlg
       Control Add Button, hDlg, %IDC_Button, "Sample Grabber", 5,20,130,25
       Dialog Show Modal hDlg Call DlgProc
    End Function
    
    CallBack Function DlgProc() As Long
       Local w,h As Long
       Select Case Cb.Msg
          Case %WM_InitDialog
             pGraph      = NewCom ClsId $CLSID_FilterGraph                              'filter graph
             pBuild      = NewCom ClsId $CLSID_CaptureGraphBuilder2                     'capture graph builder
             pSysDevEnum = NewCom ClsId $CLSID_SystemDeviceEnum                         'enumeration object
             DisplayFirstCamera
    
           Case %WM_Command
              Select Case Cb.Ctl
                 Case %IDC_Button
                    FrameGrabber
                    ? Str$(wRes) + Str$(hRes) + Str$(pBufferSize)
              End Select
    
          Case %WM_Destroy
             pGraph = Nothing
             pBuild = Nothing
             pSysDevEnum = Nothing
    
          Case %WM_Size
             Dialog Get Client hDlg To w,h
             pWindow.SetWindowPosition(150,0,w-150,h)
    
       End Select
    End Function
    
    Sub DisplayFirstCamera
       If pSysDevEnum.CreateClassEnumerator($CLSID_VideoInputDeviceCategory, pEnumCat, 0) <> %S_Ok Then Exit Sub
       pEnumCat.next(1, pMoniker, pceltFetched)                               'cycle through monikders
       pMoniker.BindToObject(Nothing, Nothing, $IID_IBaseFilter, pCap)       'create device filter for the chosen device
       pGraph.AddFilter(pCap,"First Camera")                                 'add chosen device filter to the filter graph
       pBuild.SetFilterGraph(pGraph)                                         'initialize pBuild
       pBuild.RenderStream $Pin_Category_Preview, $MediaType_Video, pCap, Nothing, Nothing   'render the live source
       pWindow = pGraph
       pWindow.Owner = hDlg
       pWindow.WindowStyle = %WS_Child Or %WS_ClipChildren Or %WS_ClipSiblings  'video window settings
       pControl = pGraph
       pControl.Run
    End Sub
    
    Sub FrameGrabber()
       'https://docs.microsoft.com/en-us/windows/win32/directshow/using-the-sample-grabber
       Local pmt As AM_Media_Type
       Local pVIH As VideoInfoHeader
    
    
       'create samplegrabber filter
       pGrabber    = NewCom ClsId $CLSID_SampleGrabber
       pGraph.AddFilter(pGrabber,"Sample Grabber")
    
       'set media type SampleGrabber will receive
       pmt.MajorType  = $MediaType_Video
       pmt.SubType    = $MediaSubType_RGB24
       pmt.FormatType = $Format_VideoInfo  '$GUID_Null
       pmt.pbFormat   = %Null
       pmt.cbFormat   = 0
       pGrabber.SetMediaType(pmt)
       pGrabber.GetConnectedMediaType(pmt)
    
       'get frame bytes
       pGrabber.SetBufferSamples %True                         'activates buffering
       pGrabber.SetOneShot %True                               'half after first sample
       pGrabber.GetCurrentBuffer pBufferSize, %Null            'call twice. 1st to get needed buffer size. not use during run time
       pGrabber.GetCurrentBuffer pBufferSize, pBuffer          'call twice. 2nd to retrieve pointer to image into pBuffer
    
       'get frame size
       pVIH = pbFormat 'pmt.FormatType
       wRes = pVIH.bmiHeader.biWidth
       hRes = pVIH.bmiHeader.biHeight
       Dialog Set Text hDlg, Str$(wRes) + Str$(hRes)
    
       pGrabber = Nothing
    End Sub
Working...
X