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

📄 capstrm.cpp

📁 传说中的 视频抓取驱动源码 啊啊啊啊啊啊啊啊啊啊啊啊啊
💻 CPP
📖 第 1 页 / 共 3 页
字号:
        ASSERT(pCurrentSrb->Irp->MdlAddress);

        StreamClassStreamNotification(  StreamRequestComplete,
                                        pCurrentSrb->StreamObject,
                                        pCurrentSrb);
    }
}

void CWDMCaptureStream::AddBuffersToDirectDraw()
{
    KIRQL Irql;
    BOOL  fAdded;
    
    KeAcquireSpinLock(&m_streamDataLock, &Irql);
    
    while (!IsListEmpty(&m_incomingDataSrbQueue))
    {
        // So if we've reached this point, we are in the run state, and
        // we have an SRB on our incoming queue, and we are holding the
        // the stream lock
        PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)RemoveHeadList(&m_incomingDataSrbQueue);
        PHW_STREAM_REQUEST_BLOCK pSrb = pSrbExt->pSrb;

        // Calls to DXAPI must be at Passive level, so release the spinlock temporarily

        KeReleaseSpinLock(&m_streamDataLock, Irql);

        DBGINFO(("Removed 0x%x from data queue\n", pSrb));

        fAdded = AddBuffer(pSrb);

        KeAcquireSpinLock(&m_streamDataLock, &Irql);

        if (fAdded)
        {
            DBGINFO(("Adding 0x%x to wait queue\n", pSrb));
            InsertTailList(&m_waitQueue, &pSrbExt->srbListEntry);
        }
        else
        {
            DBGINFO(("Adding 0x%x back to dataqueue\n", pSrb));

            // put it back where it was
            InsertHeadList(&m_incomingDataSrbQueue, &pSrbExt->srbListEntry);
            break;
        }
    }
    KeReleaseSpinLock(&m_streamDataLock, Irql);
}


BOOL CWDMCaptureStream::AddBuffer(PHW_STREAM_REQUEST_BLOCK pSrb)
{
    DDADDVPCAPTUREBUFF ddAddVPCaptureBuffIn;
    DWORD ddOut = DD_OK;

    PIRP irp = pSrb->Irp;
    PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)pSrb->SRBExtension;
    
    DBGINFO(("In AddBuffer. pSrb: 0x%x.\n", pSrb));

    // For handling full-screen DOS, res changes, etc.
    if (m_hCapture == 0)
    {
        if (!GetCaptureHandle())
        {
            return FALSE;
        }
    }

    ddAddVPCaptureBuffIn.hCapture = m_hCapture;
    ddAddVPCaptureBuffIn.dwFlags = DDADDBUFF_SYSTEMMEMORY;
    ddAddVPCaptureBuffIn.pMDL = irp->MdlAddress;

    ddAddVPCaptureBuffIn.lpBuffInfo = &pSrbExt->ddCapBuffInfo;
    ddAddVPCaptureBuffIn.pKEvent = &pSrbExt->bufferDoneEvent;

    DxApi(DD_DXAPI_ADDVPCAPTUREBUFFER, &ddAddVPCaptureBuffIn, sizeof(ddAddVPCaptureBuffIn), &ddOut, sizeof(ddOut));

    if (ddOut != DD_OK)
    {
        // Not necessarily an error.
        DBGINFO(("DD_DXAPI_ADDVPCAPTUREBUFFER failed.\n"));
        // TRAP();
        return FALSE;
    }

    return TRUE;
}


VOID CWDMCaptureStream::HandleStateTransition()
{
    KIRQL Irql;
    switch (m_stateChange)
    {
        case Running:
            AddBuffersToDirectDraw();
            m_stateChange = ChangeComplete;
            KeSetEvent(&m_specialEvent, 0, FALSE);
            break;

        case Pausing:
            KeAcquireSpinLock(&m_streamDataLock, &Irql);
            if (IsListEmpty(&m_waitQueue))
            {
                KeReleaseSpinLock(&m_streamDataLock, Irql);
                m_stateChange = ChangeComplete;
                KeSetEvent(&m_specialEvent, 0, FALSE);
            }
            else
            {
                KeReleaseSpinLock(&m_streamDataLock, Irql);
            }
            break;

        case Stopping:
            KeAcquireSpinLock(&m_streamDataLock, &Irql);
            if (IsListEmpty(&m_waitQueue))
            {
                KeReleaseSpinLock(&m_streamDataLock, Irql);
                EmptyIncomingDataSrbQueue();
                m_stateChange = ChangeComplete;
                KeSetEvent(&m_specialEvent, 0, FALSE);
            }
            else
            {
                KeReleaseSpinLock(&m_streamDataLock, Irql);
            }
            break;

        case Closing:
            m_stateChange = ChangeComplete;
            KeSetEvent(&m_specialEvent, 0, FALSE);
            DBGTRACE(("StreamThread exiting\n"));
            
            PsTerminateSystemThread(STATUS_SUCCESS);

            DBGERROR(("Shouldn't get here\n"));
            TRAP();
            break;

        case ChangeComplete:
            DBGTRACE(("Must have completed transition in HandleBusMasterCompletion\n"));
            break;

        default:
            TRAP();
            break;
    }
}

    
BOOL CWDMCaptureStream::ResetFieldNumber()
{
    int                     streamNumber = m_pStreamObject->StreamNumber;
    DDSETFIELDNUM           ddSetFieldNum;
    DWORD                   ddOut;

    ASSERT(streamNumber == STREAM_VideoCapture || streamNumber == STREAM_VBICapture);

    if (m_pVideoPort->GetDirectDrawHandle() == 0) {
        DBGERROR(("Didn't expect ring0DirectDrawHandle to be zero.\n"));
        TRAP();
        return FALSE;
    }
    
    if (m_pVideoPort->GetVideoPortHandle() == 0) {
        DBGERROR(("Didn't expect ring0VideoPortHandle to be zero.\n"));
        TRAP();
        return FALSE;
    }
    
    RtlZeroMemory(&ddSetFieldNum, sizeof(ddSetFieldNum));
    RtlZeroMemory(&ddOut, sizeof(ddOut));

    KSPROPERTY_DROPPEDFRAMES_CURRENT_S DroppedFrames;
    GetDroppedFrames(&DroppedFrames);

    ddSetFieldNum.hDirectDraw = m_pVideoPort->GetDirectDrawHandle();
    ddSetFieldNum.hVideoPort = m_pVideoPort->GetVideoPortHandle();
    ddSetFieldNum.dwFieldNum = ((ULONG)DroppedFrames.PictureNumber + 1) * GetFieldInterval();
    
    DxApi(DD_DXAPI_SET_VP_FIELD_NUMBER, &ddSetFieldNum, sizeof(ddSetFieldNum), &ddOut, sizeof(ddOut));

    if (ddOut != DD_OK)
    {
        DBGERROR(("DD_DXAPI_SET_VP_FIELD_NUMBER failed.\n"));
        TRAP();
        return FALSE;
    }
    else
    {
#ifdef DEBUG
        DBGINFO(("PictureNumber: %d; ", DroppedFrames.PictureNumber));
        DBGINFO(("DropCount: %d\n", DroppedFrames.DropCount));
        DBGINFO(("AverageFrameSize: %d\n", DroppedFrames.AverageFrameSize));
#endif
        return TRUE;
    }
}

BOOL CWDMCaptureStream::FlushBuffers()
{
    DWORD ddOut = DD_OK;

    // commented out the trap because it is possible that capture handle is closed in DD before flushbuffer is called during mode switch
    if (m_hCapture == NULL) {
       //DBGERROR(("m_hCapture === NULL in FlushBuffers.\n"));
       //TRAP();
       return FALSE;
    }

    DxApi(DD_DXAPI_FLUSHVPCAPTUREBUFFERS, &m_hCapture, sizeof(HANDLE), &ddOut, sizeof(ddOut));

    if (ddOut != DD_OK)
    {
        DBGERROR(("DD_DXAPI_FLUSHVPCAPTUREBUFFERS failed.\n"));
        TRAP();
        return FALSE;
    }
    else
    {
        return TRUE;
    }
}
    

VOID CWDMCaptureStream::TimeStampSrb(PHW_STREAM_REQUEST_BLOCK pSrb)
{
    PKSSTREAM_HEADER    pDataPacket = pSrb->CommandData.DataBufferArray;
    PSRB_DATA_EXTENSION      pSrbExt = (PSRB_DATA_EXTENSION)pSrb->SRBExtension;

    pDataPacket->Duration = GetFieldInterval() * NTSCFieldDuration;

    pDataPacket->OptionsFlags |= 
        KSSTREAM_HEADER_OPTIONSF_DURATIONVALID |
        KSSTREAM_HEADER_OPTIONSF_SPLICEPOINT;

    // Find out what time it is, if we're using a clock

    if (m_hMasterClock) {
        LARGE_INTEGER Delta;

        HW_TIME_CONTEXT TimeContext;

//        TimeContext.HwDeviceExtension = pHwDevExt; 
        TimeContext.HwDeviceExtension = (struct _HW_DEVICE_EXTENSION *)m_pVideoDecoder; 
        TimeContext.HwStreamObject = m_pStreamObject;
        TimeContext.Function = TIME_GET_STREAM_TIME;

        StreamClassQueryMasterClockSync (
            m_hMasterClock,
            &TimeContext);

        // This calculation should result in the stream time WHEN the buffer
        // was filled.
        Delta.QuadPart = TimeContext.SystemTime -
                            pSrbExt->ddCapBuffInfo.liTimeStamp.QuadPart;

        // Be safe, just use the current stream time, without the correction for when
        // DDraw actually returned the buffer to us.
        pDataPacket->PresentationTime.Time = TimeContext.Time; 

#ifdef THIS_SHOULD_WORK_BUT_IT_DOESNT
        if (TimeContext.Time > (ULONGLONG) Delta.QuadPart)
        {
            pDataPacket->PresentationTime.Time = TimeContext.Time - Delta.QuadPart;
        }
        else
        {
            // There's a bug in Ks or Stream after running for 2 hours
            // that makes this hack necessary.  Will be fixed soon...
            pDataPacket->PresentationTime.Time = TimeContext.Time;
        }
#endif

#ifdef DEBUG
        ULONG *tmp1, *tmp2;

        tmp1 = (ULONG *)&pDataPacket->PresentationTime.Time;
        tmp2 = (ULONG *)&TimeContext.Time;
        DBGINFO(("PT: 0x%x%x; ST: 0x%x%x\n", tmp1[1], tmp1[0], tmp2[1], tmp2[0]));
#endif

        pDataPacket->PresentationTime.Numerator = 1;
        pDataPacket->PresentationTime.Denominator = 1;

        pDataPacket->OptionsFlags |= 
            KSSTREAM_HEADER_OPTIONSF_TIMEVALID;
    }
    else
    {
        pDataPacket->OptionsFlags &= 
            ~KSSTREAM_HEADER_OPTIONSF_TIMEVALID;
    }
}


void CWDMCaptureStream::CancelPacket( PHW_STREAM_REQUEST_BLOCK pSrbToCancel)
{
    PHW_STREAM_REQUEST_BLOCK    pCurrentSrb;
    KIRQL                       Irql;
    PLIST_ENTRY                 Entry;
    BOOL                        bFound = FALSE;

    if ( m_stateChange == Initializing )  // Stream not completely setup, so nothing in the queue
    {
        DBGINFO(( "Bt829: Didn't find Srb 0x%x\n", pSrbToCancel));
        return;
    }

    KeAcquireSpinLock( &m_streamDataLock, &Irql);

    Entry = m_incomingDataSrbQueue.Flink;

    // 
    // Loop through the linked list from the beginning to end,
    // trying to find the SRB to cancel
    //
    while( Entry != &m_incomingDataSrbQueue)
    {
        PSRB_DATA_EXTENSION pSrbExt;
    
        pSrbExt = ( PSRB_DATA_EXTENSION)Entry;
        pCurrentSrb = pSrbExt->pSrb;
        
        if( pCurrentSrb == pSrbToCancel)
        {
            RemoveEntryList( Entry);
            bFound = TRUE;
            break;
        }
        Entry = Entry->Flink;
    }

    KeReleaseSpinLock( &m_streamDataLock, Irql);

    if( bFound)
    {
        pCurrentSrb->Status = STATUS_CANCELLED;
        pCurrentSrb->CommandData.DataBufferArray->DataUsed = 0;
        
        DBGINFO(( "Bt829: Cancelled Srb 0x%x\n", pCurrentSrb));
        StreamClassStreamNotification( StreamRequestComplete,
                                       pCurrentSrb->StreamObject,
                                       pCurrentSrb);
    }
    else
    {
        // If this is a DATA_TRANSFER and a STREAM_REQUEST SRB, 
        // then it must be in the waitQueue, being filled by DDraw.

        // If so, mark it cancelled, and it will 
        // be returned when  DDraw is finished with it.
        if(( pSrbToCancel->Flags & (SRB_HW_FLAGS_DATA_TRANSFER | SRB_HW_FLAGS_STREAM_REQUEST)) ==
                                  (SRB_HW_FLAGS_DATA_TRANSFER | SRB_HW_FLAGS_STREAM_REQUEST))
        {
            pSrbToCancel->Status = STATUS_CANCELLED;
            DBGINFO(( "Bt829: Cancelled Srb on waitQueue 0x%x\n", pSrbToCancel));
        }
        else 
        {
           DBGINFO(( "Bt829: Didn't find Srb 0x%x\n", pSrbToCancel));
        }
    }
}

⌨️ 快捷键说明

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