⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 capstrm.cpp

📁 传说中的 视频抓取驱动源码 啊啊啊啊啊啊啊啊啊啊啊啊啊
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//==========================================================================;
//
//  CWDMCaptureStream - Capture Stream base class implementation
//
//      $Date:   22 Feb 1999 15:13:58  $
//  $Revision:   1.1  $
//    $Author:   KLEBANOV  $
//
// $Copyright:  (c) 1997 - 1998  ATI Technologies Inc.  All Rights Reserved.  $
//
//==========================================================================;

extern "C"
{
#include "strmini.h"
#include "ksmedia.h"

#include "ddkmapi.h"
}

#include "wdmvdec.h"
#include "wdmdrv.h"
#include "aticonfg.h"
#include "capdebug.h"
#include "defaults.h"
#include "winerror.h"


void CWDMCaptureStream::TimeoutPacket(IN OUT PHW_STREAM_REQUEST_BLOCK pSrb)
{
    if (m_KSState == KSSTATE_STOP || !m_pVideoDecoder->PreEventOccurred())
    {
        DBGTRACE(("Attempting to complete Srbs.\n"));
        EmptyIncomingDataSrbQueue();
    }
}


void CWDMCaptureStream::Startup(PUINT puiErrorCode) 
{
    KIRQL Irql;
    DBGTRACE(("CWDMCaptureStream::Startup()\n"));

    KeInitializeEvent(&m_specialEvent, SynchronizationEvent, FALSE);
    KeInitializeEvent(&m_stateTransitionEvent, SynchronizationEvent, FALSE);
    KeInitializeEvent(&m_SrbAvailableEvent, SynchronizationEvent, FALSE);

    KeInitializeSpinLock(&m_streamDataLock);

    KeAcquireSpinLock(&m_streamDataLock, &Irql);

    InitializeListHead(&m_incomingDataSrbQueue);
    InitializeListHead(&m_waitQueue);
    InitializeListHead(&m_reversalQueue);

    KeReleaseSpinLock(&m_streamDataLock, Irql);
    
    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
    
    ASSERT(m_stateChange == Initializing);
    m_stateChange = Starting;
    
    HANDLE  threadHandle;
    NTSTATUS status = PsCreateSystemThread(&threadHandle,
                                    (ACCESS_MASK) 0L,
                                    NULL,
                                    NULL,
                                    NULL,
                                    (PKSTART_ROUTINE) ThreadStart,
                                    (PVOID) this);
    if (status != STATUS_SUCCESS)
    {
        DBGERROR(("CreateStreamThread failed\n"));
        *puiErrorCode = WDMMINI_ERROR_MEMORYALLOCATION;
        return;
    }

    // Don't need this for anything, so might as well close it now.
    // The thread will call PsTerminateThread on itself when it
    // is done.
    ZwClose(threadHandle);

    KeWaitForSingleObject(&m_specialEvent, Suspended, KernelMode, FALSE, NULL);
    ASSERT(m_stateChange == ChangeComplete);
    
    DBGTRACE(("SrbOpenStream got notification that thread started\n"));
    *puiErrorCode = WDMMINI_NOERROR;
}


void CWDMCaptureStream::Shutdown()
{
    KIRQL                   Irql;

      DBGTRACE(("CWDMCaptureStream::Shutdown()\n"));

    if ( m_stateChange != Initializing )
    {
        ASSERT(m_stateChange == ChangeComplete);
        m_stateChange = Closing;
        KeResetEvent(&m_specialEvent);
        KeSetEvent(&m_stateTransitionEvent, 0, TRUE);
        KeWaitForSingleObject(&m_specialEvent, Suspended, KernelMode, FALSE, NULL);
        ASSERT(m_stateChange == ChangeComplete);
    

        KeAcquireSpinLock(&m_streamDataLock, &Irql);
        if (!IsListEmpty(&m_incomingDataSrbQueue))
        {
            TRAP();
        }

        if (!IsListEmpty(&m_waitQueue))
        {
            TRAP();
        }
        KeReleaseSpinLock(&m_streamDataLock, Irql);
    }

    ReleaseCaptureHandle();
}


void CWDMCaptureStream::ThreadProc()
{
    PHW_STREAM_REQUEST_BLOCK pCurrentSrb = NULL;
    PSRB_DATA_EXTENSION pSrbExt = NULL;
    KEVENT DummyEvent;
    const int numEvents = 3;

    NTSTATUS status;

    // Wo unto you if you overrun this array
    PVOID eventArray[numEvents];

    KeInitializeEvent(&DummyEvent, SynchronizationEvent, FALSE);

    ASSERT(m_stateChange == Starting);

    // Indicates to SrbOpenStream() to continue
    m_stateChange = ChangeComplete;
    KeSetEvent(&m_specialEvent, 0, FALSE);

    // These should remain constant the whole time
    eventArray[0] = &m_stateTransitionEvent;
    eventArray[1] = &m_SrbAvailableEvent;

    // eventArray[2] changes, so it is set below

    // This runs until the thread terminates itself
    // inside of HandleStateTransition
    while (1)
    {
// May not be necessary
#define ENABLE_TIMEOUT
#ifdef ENABLE_TIMEOUT
        LARGE_INTEGER i;
#endif

        if (pCurrentSrb == NULL)
        {
            pSrbExt = (PSRB_DATA_EXTENSION)ExInterlockedRemoveHeadList(&m_waitQueue, &m_streamDataLock);

            if (pSrbExt)
            {
                pCurrentSrb = pSrbExt->pSrb;
                eventArray[2] = &pSrbExt->bufferDoneEvent;
            }
            else
            {
#ifdef DEBUG
                if (m_KSState == KSSTATE_RUN &&
                    m_stateChange == ChangeComplete &&
                    m_pVideoDecoder->PreEventOccurred() == FALSE)
                {
                    static int j;

                    // Indicates that we are starved for buffers. Probably
                    // a higher level is not handing them to us in a timely
                    // fashion for some reason
                    DBGPRINTF((" S "));
                    if ((++j % 10) == 0)
                    {
                        DBGPRINTF(("\n"));
                    }
                }
#endif
                pCurrentSrb = NULL;
                eventArray[2] = &DummyEvent;
            }
        }

#ifdef ENABLE_TIMEOUT
        // This is meant mainly as a failsafe measure.
        i.QuadPart = -2000000;      // 200 ms
#endif
        
        status = KeWaitForMultipleObjects(  numEvents,  // count
                                            eventArray, // DispatcherObjectArray
                                            WaitAny,    // WaitType
                                            Executive,  // WaitReason
                                            KernelMode, // WaitMode
                                            FALSE,      // Alertable
#ifdef ENABLE_TIMEOUT
                                            &i,         // Timeout (Optional)
#else
                                            NULL,
#endif
                                            NULL);      // WaitBlockArray (Optional)

        switch (status)
        {
            // State transition. May including killing this very thread
            case 0:
                if ( pCurrentSrb )
                {
                  ExInterlockedInsertHeadList( &m_waitQueue, &pSrbExt->srbListEntry, &m_streamDataLock );
                  pCurrentSrb = NULL;
                }
                HandleStateTransition();
                break;

            // New Srb available
            case 1:
                if ( pCurrentSrb )
                {
                  ExInterlockedInsertHeadList( &m_waitQueue, &pSrbExt->srbListEntry, &m_streamDataLock );
                  pCurrentSrb = NULL;
                }
                if (m_KSState == KSSTATE_RUN && m_stateChange == ChangeComplete)
                {
                    AddBuffersToDirectDraw();
                }
                break;

            // Busmaster complete
            case 2:
                if ( pCurrentSrb )
                {
                    HandleBusmasterCompletion(pCurrentSrb);
                    pCurrentSrb = NULL;
                }
                break;

#ifdef ENABLE_TIMEOUT
            // If we timeout in the RUN state, this is our chance to try again
            // to add buffers. May not be necessary, since currently, we go
            // through a state transition for DOS boxes, etc.
            case STATUS_TIMEOUT:
                if ( pCurrentSrb )
                {
                  ExInterlockedInsertHeadList( &m_waitQueue, &pSrbExt->srbListEntry, &m_streamDataLock );
                  pCurrentSrb = NULL;
                }
                if (m_KSState == KSSTATE_RUN &&
                    m_stateChange == ChangeComplete &&
                    m_pVideoDecoder->PreEventOccurred() == FALSE)
                {
                    AddBuffersToDirectDraw();
                }
                break;
#endif

            default:
                TRAP();
                break;
        }
    }
}


VOID STREAMAPI CWDMCaptureStream::VideoReceiveDataPacket(IN PHW_STREAM_REQUEST_BLOCK pSrb)
{
    KIRQL                   Irql;
    PSRB_DATA_EXTENSION          pSrbExt;

    ASSERT(pSrb->Irp->MdlAddress);
    
    DBGINFO(("Receiving SD---- SRB=%x\n", pSrb));

    pSrb->Status = STATUS_SUCCESS;

    switch (pSrb->Command) {

        case SRB_READ_DATA:

            // Rule: 
            // Only accept read requests when in either the Pause or Run
            // States.  If Stopped, immediately return the SRB.

            if ( (m_KSState == KSSTATE_STOP) || ( m_stateChange == Initializing ) ) {
                StreamClassStreamNotification(  StreamRequestComplete,
                                                pSrb->StreamObject,
                                                pSrb);
                break;
            } 

            pSrbExt = (PSRB_DATA_EXTENSION)pSrb->SRBExtension;
            RtlZeroMemory (pSrbExt, sizeof (SRB_DATA_EXTENSION));
            pSrbExt->pSrb = pSrb;
            KeInitializeEvent(&pSrbExt->bufferDoneEvent, SynchronizationEvent, FALSE);

            DBGINFO(("Adding 0x%x to data queue\n", pSrb));

            KeAcquireSpinLock(&m_streamDataLock, &Irql);
            InsertTailList(&m_incomingDataSrbQueue, &pSrbExt->srbListEntry);
            KeReleaseSpinLock(&m_streamDataLock, Irql);
            KeSetEvent(&m_SrbAvailableEvent, 0, FALSE);

            break;

        default:

            //
            // invalid / unsupported command. Fail it as such
            //

            TRAP();

            pSrb->Status = STATUS_NOT_IMPLEMENTED;
            StreamClassStreamNotification(  StreamRequestComplete,
                                            pSrb->StreamObject,
                                            pSrb);
            break;
    }
}

/*
** VideoGetProperty()
**
**    Routine to process video property requests
**
** Arguments:
**
**    pSrb - pointer to the stream request block for properties
**
** Returns:
**
** Side Effects:  none
*/

VOID CWDMCaptureStream::VideoGetProperty(PHW_STREAM_REQUEST_BLOCK pSrb)
{
    PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;

    if (IsEqualGUID (KSPROPSETID_Connection, pSPD->Property->Set)) {
        VideoStreamGetConnectionProperty (pSrb);
    }
    else if (IsEqualGUID (PROPSETID_VIDCAP_DROPPEDFRAMES, pSPD->Property->Set)) {
        VideoStreamGetDroppedFramesProperty (pSrb);
    }
    else {
       pSrb->Status = STATUS_NOT_IMPLEMENTED;
    }
}


/*
** VideoSetState()
**
**    Sets the current state of the requested stream
**
** Arguments:
**
**    pSrb - pointer to the stream request block for properties
**    BOOL bVPVBIConnected
**    BOOL bVPConnected
**
** Returns:
**
** Side Effects:  none

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -