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

📄 basestrm.cpp

📁 采集卡的驱动编程,具有较大的参考价值,特别开发视频采集的软件工程师有用
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// basestrm.cpp - base class for streams of Video Capture sample
//=============================================================================
//
// Compuware Corporation
// NuMega Lab
// 9 Townsend West
// Nashua, NH 03060  USA
//
// Copyright (c) 1998 Compuware Corporation. All Rights Reserved.
// Unpublished - rights reserved under the Copyright laws of the
// United States.
//
//=============================================================================

#include <vdw.h>
#include <kstream.h>

#include "basestrm.h"

#ifdef __VIDCAP_TRACEON__
	KTrace TVS("VidCap Classes");
#endif


DEFINE_KSPROPERTY_TABLE(VidcapBaseStream::m_VideoStreamConnectionProperties)
{
    DEFINE_KSPROPERTY_ITEM
    (
        KSPROPERTY_CONNECTION_ALLOCATORFRAMING,
        TRUE,										// GetSupported or Handler
        sizeof(KSPROPERTY),							// MinProperty
        sizeof(KSALLOCATOR_FRAMING),				// MinData
        FALSE,										// SetSupported or Handler
        NULL,										// Values
        0,											// RelationsCount
        NULL,										// Relations
        NULL,										// SupportHandler
        sizeof(ULONG)								// SerializedSize
    ),
};

DEFINE_KSPROPERTY_TABLE(VidcapBaseStream::m_VideoStreamDroppedFramesProperties)
{
    DEFINE_KSPROPERTY_ITEM
    (
        KSPROPERTY_DROPPEDFRAMES_CURRENT,
        TRUE,										// GetSupported or Handler
        sizeof(KSPROPERTY_DROPPEDFRAMES_CURRENT_S),	// MinProperty
        sizeof(KSPROPERTY_DROPPEDFRAMES_CURRENT_S),	// MinData
        FALSE,										// SetSupported or Handler
        NULL,										// Values
        0,											// RelationsCount
        NULL,										// Relations
        NULL,										// SupportHandler
        0											// SerializedSize
    ),
};


// ------------------------------------------------------------------------
// Array of all of the property sets supported by video streams
// ------------------------------------------------------------------------

DEFINE_KSPROPERTY_SET_TABLE(VidcapBaseStream::m_VideoStreamProperties)
{
    DEFINE_KSPROPERTY_SET
    ( 
        &KSPROPSETID_Connection,							// Set
        SIZEOF_ARRAY(m_VideoStreamConnectionProperties),	// PropertiesCount
        m_VideoStreamConnectionProperties,					// PropertyItem
        0,													// FastIoCount
        NULL												// FastIoTable
    ),
    DEFINE_KSPROPERTY_SET
    ( 
        &PROPSETID_VIDCAP_DROPPEDFRAMES,					// Set
        SIZEOF_ARRAY(m_VideoStreamDroppedFramesProperties), // PropertiesCount
        m_VideoStreamDroppedFramesProperties,               // PropertyItem
        0,													// FastIoCount
        NULL												// FastIoTable
    ),
};


const ULONG	VidcapBaseStream::m_VideoStreamPropertiesCount = SIZEOF_ARRAY(m_VideoStreamProperties);

VidcapBaseStream::VidcapBaseStream()
	: KStream(),
	  m_RequestQueueCount(0),
	  m_pVideoInfoHeader(NULL),
	  m_fDiscontinuity(0),
	  m_QST_Now(0),
	  m_QST_NextFrame(0),
	  m_QST_StreamTime(0)

{
	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::VidcapBaseStream -- constructing\n";
	#endif

	RtlZeroMemory(&m_FrameInfo, sizeof(KS_FRAME_INFO));   // PictureNumber, etc.
    for (int i = 0; i < (720*3); i++)
		m_LineBuffer[i] =  0;	 // working buffer (RGB24)
}

// -- our version of InitializeBaseClass called from derived stream classes --
void VidcapBaseStream::InitializeBaseClass(const HW_STREAM_INFORMATION& info, ULONG uStreamHeaderMediaSpecific)
{
	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::InitializeBaseClass -- calling KStream::InitializeBaseClass\n";
	#endif

	KStream::InitializeBaseClass(
		info,
		0,							 // uClockSupportFlags 
		FALSE,						 // Not a master clock
		FALSE,						 // bDma
		TRUE,						 // bPio,
	    uStreamHeaderMediaSpecific,	 // StreamHeaderMediaSpecific
	    0 );						 // StreamHeaderWorkspace 

}

void VidcapBaseStream::QueueSrb(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::QueueSrb -- Start\n";
	#endif

	PIRP pIrp(pSrb->Irp);

	// -- make the SRB part of the Irp's Driver Context and 
	//		then QUEUE the IRP on our IRP Queue --
	Lock();

	pIrp->Tail.Overlay.DriverContext[0] = pSrb;
	m_RequestQueue.InsertTail(pIrp);
	m_RequestQueueCount++;	

	Unlock();

	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::QueueSrb -- End\n";
	#endif

}

PHW_STREAM_REQUEST_BLOCK VidcapBaseStream::DequeueSrb(void)
{
	// -- excessive tracing use for DEBUG only! --
	//	#ifdef __VIDCAP_TRACEON__
	//	TVS << TraceInfo << "VidcapBaseStream::DequeueSrb -- Start\n";
	//	#endif

	PHW_STREAM_REQUEST_BLOCK pSrb = NULL;

	// -- since the SRB actually contains the IRP, and our 
	//		driver context of the IRP now points to the SRB,
	//		we can dequeue the IRP, pull of the SRB and return
	//		only that object... the IRP is already pointed to
	//		BY the SRB itself! --

	Lock();

	if (!m_RequestQueue.IsEmpty())
	{
		PIRP pIrp = m_RequestQueue.RemoveHead();
		pSrb = (PHW_STREAM_REQUEST_BLOCK)pIrp->Tail.Overlay.DriverContext[0];
		m_RequestQueueCount--;	
	}
	else
		pSrb = NULL;

	Unlock();

	// -- excessive tracing use for DEBUG only! --
	//	#ifdef __VIDCAP_TRACEON__
	//	TVS << TraceInfo << "VidcapBaseStream::DequeueSrb -- End\n";
	//	#endif

	return pSrb;
}

void VidcapBaseStream::CancelAllRequests(void)
{
	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::CancelAllRequests -- Start\n";
	#endif

	PHW_STREAM_REQUEST_BLOCK pSrb;

	Lock();

	while ( !m_RequestQueue.IsEmpty() )
	{
		PIRP pIrp = m_RequestQueue.RemoveHead();
		pSrb = (PHW_STREAM_REQUEST_BLOCK)pIrp->Tail.Overlay.DriverContext[0];
		m_RequestQueueCount--;	
		pSrb->CommandData.DataBufferArray->DataUsed = 0;
		RequestComplete(pSrb);
		// pSrb->Status = ??
	}
			
	Unlock();

	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::CancelAllRequests -- End\n";
	#endif

}

void VidcapBaseStream::CancelRequest(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::CancelAllRequests -- Start\n";
	#endif

	PIRP pIrp;
	BOOLEAN Removed=FALSE;

	Lock();

	for (pIrp=m_RequestQueue.Head(); pIrp!=NULL; pIrp=m_RequestQueue.Next(pIrp))
	{
		if (pIrp->Tail.Overlay.DriverContext[0] == pSrb)
		{
			m_RequestQueue.Remove(pIrp);
			m_RequestQueueCount--;	
			Removed = TRUE;
			break;
		}
	}

	Unlock();

	if (Removed)
	{
		pSrb->CommandData.DataBufferArray->DataUsed = 0;
		RequestComplete(pSrb);
	}

	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::CancelAllRequests -- End\n";
	#endif

}

void VidcapBaseStream::DispatchControl(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::DispatchControl -- Start\n";
	#endif

	if ( !m_ControlSrbList.AddIfBusy(pSrb) )
		do 
		{
			pSrb->Status = STATUS_SUCCESS; // default is success
			KStream::DispatchControl(pSrb);

		} while ( m_ControlSrbList.RemoveIfAvailable(pSrb) );

	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::DispatchControl -- End\n";
	#endif

}

void VidcapBaseStream::OnGetProperty(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::OnGetProperty -- Start\n";
	#endif

	PSTREAM_PROPERTY_DESCRIPTOR pSPD = pSrb->CommandData.PropertyInfo;

	if (IsEqualGUID (KSPROPSETID_Connection, pSPD->Property->Set))
		GetConnectionProperty(pSrb);

	else if (IsEqualGUID (PROPSETID_VIDCAP_DROPPEDFRAMES, pSPD->Property->Set))
		GetDroppedFramesProperty(pSrb);

	else 
	   pSrb->Status = STATUS_NOT_IMPLEMENTED;

	NextSrb(pSrb, pSrb->Status);

	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::OnGetProperty -- End\n";
	#endif

}


void VidcapBaseStream::OnGetState(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::OnGetState -- Start\n";
	#endif

	pSrb->CommandData.StreamState = m_eState;
	pSrb->ActualBytesTransferred = sizeof (KSSTATE);

	// A very odd rule:
	// When transitioning from stop to pause, DShow tries to preroll
	// the graph.  Capture sources can't preroll, and indicate this
	// by returning VFW_S_CANT_CUE in user mode.  To indicate this
	// condition from drivers, they must return STATUS_NO_DATA_DETECTED

	if (m_eState == KSSTATE_PAUSE)
	{
		#ifdef __VIDCAP_TRACEON__
		TVS << TraceInfo << "VidcapBaseStream::OnGetState -- Paused, returning STATUS_NO_DATA_DETECTED\n";
		#endif

		NextSrb(pSrb,STATUS_NO_DATA_DETECTED);
	}
	else
	   NextSrb(pSrb,STATUS_SUCCESS);

	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::OnGetState -- End\n";
	#endif

}

void VidcapBaseStream::OnSetState(PHW_STREAM_REQUEST_BLOCK pSrb)
{
	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::OnSetState -- Start\n";
	#endif

	KSSTATE    PreviousState;

    //
    // For each stream, the following states are used:
    // 
    // Stop:    Absolute minimum resources are used.  No outstanding IRPs.
    // Acquire: KS only state that has no DirectShow correpondence
    //          Acquire needed resources.
    // Pause:   Getting ready to run.  Allocate needed resources so that 
    //          the eventual transition to Run is as fast as possible.
    //          Read SRBs will be queued at either the Stream class 
    //          or in your driver (depending on when you send "ReadyForNext")
    //          and whether you're using the Stream class for synchronization
    // Run:     Streaming. 
    //
    // Moving to Stop to Run always transitions through Pause.
    //
    // But since a client app could crash unexpectedly, drivers should handle
    // the situation of having outstanding IRPs cancelled and open streams
    // being closed WHILE THEY ARE STREAMING!
    //
    // Note that it is quite possible to transition repeatedly between states:
    // Stop -> Pause -> Stop -> Pause -> Run -> Pause -> Run -> Pause -> Stop
    //

    //
    // Remember the state we're transitioning away from
    //

    PreviousState = m_eState;

    //
    // Set the new state
    //

    m_eState = pSrb->CommandData.StreamState;

    switch (m_eState)  

    {
    case KSSTATE_STOP:

        //
        // The stream class will cancel all outstanding IRPs for us
        // (but only if it is maintaining the queue ie. using Stream Class synchronization)
        // Since Testcap is not using Stream Class synchronization, we must clear the queue here
		#ifdef __VIDCAP_TRACEON__
		TVS << TraceAlways << "VidcapBaseStream::OnSetState -- New State = KSSTATE_STOP\n";
		#endif

        CancelAllRequests();

        break;

    case KSSTATE_ACQUIRE:

        //
        // This is a KS only state, that has no correspondence in DirectShow
        // 
		#ifdef __VIDCAP_TRACEON__
		TVS << TraceAlways << "VidcapBaseStream::OnSetState -- New State = KSSTATE_ACQUIRE\n";
		#endif
        break;

    case KSSTATE_PAUSE:

        //
        // On a transition to pause from acquire or stop, start our timer running.
        //
		#ifdef __VIDCAP_TRACEON__
		TVS << TraceAlways << "VidcapBaseStream::OnSetState -- New State = KSSTATE_PAUSE\n";
		#endif

        if (PreviousState == KSSTATE_ACQUIRE || PreviousState == KSSTATE_STOP)
		{  

            // Zero the frame counters
            m_FrameInfo.PictureNumber = 0;
            m_FrameInfo.DropCount = 0;
            m_FrameInfo.dwFrameFlags = 0;

            // Setup the next timer callback
            // Make it run at 2x the requested capture rate (which is in 100nS units)

            StreamClassScheduleTimer (
                    pSrb->StreamObject,									// StreamObject
                    Adapter(),											// HwDeviceExtension
                    (ULONG) (m_pVideoInfoHeader->AvgTimePerFrame / 20), // Microseconds
                    VideoTimerRoutine,									// TimerRoutine
                    this);												// Context (also this stream)
        }
        break;

    case KSSTATE_RUN:

        // 
        // Begin Streaming.
        //
		#ifdef __VIDCAP_TRACEON__
		TVS << TraceAlways << "VidcapBaseStream::OnSetState -- New State = KSSTATE_RUN\n";
		#endif

        // Reset the discontinuity flag

        m_fDiscontinuity = FALSE;

        // Setting the NextFrame time to zero will cause the value to be
        // reset from the stream time 

        m_QST_NextFrame = 0;

        break;

    } // end switch (pSrb->CommandData.StreamState)  
	
	NextSrb(pSrb);

	#ifdef __VIDCAP_TRACEON__
	TVS << TraceInfo << "VidcapBaseStream::OnSetState -- End\n";
	#endif

}

// -- used in this sample for generating video frames --
void STREAMAPI VidcapBaseStream::VideoTimerRoutine(PVOID pContext)
{
	//	-- this trace tends to really make the monitor go crazy! --
	//	#ifdef __VIDCAP_TRACEON__
	//	TVS << TraceInfo << "VidcapBaseStream::VideoTimerRoutine\n";
	//	#endif

	((VidcapBaseStream*)pContext)->OnVideoTimer();
}

// -- can be overridden in derived classes to generate video for that class --
void VidcapBaseStream::OnVideoTimer()
{
    // If we're stopped and the timer is still running, just return.
    // This will stop the timer.
	//  -- excessive tracing... use during DEBUG only! --
	//	#ifdef __VIDCAP_TRACEON__
	//	TVS << TraceInfo << "VidcapBaseStream::OnVideoTimer -- Start\n";
	//	#endif

    if (KSSTATE_STOP == m_eState)
	{  
		#ifdef __VIDCAP_TRACEON__
		TVS << TraceAlways << "VidcapBaseStream::OnVideoTimer -- State = KSSTATE_STOP... returning\n";
		#endif

		return;
    }

    // Capture a frame if it's time and we have a buffer

    CaptureFrame();

    // Schedule the next timer event
    // Make it run at 2x the requested capture rate (which is in 100nS units)

⌨️ 快捷键说明

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