//==========================================================================; // // CWDMVideoCaptureStream - Video Capture Stream class implementation // // $Date: 05 Aug 1998 11:11:00 $ // $Revision: 1.0 $ // $Author: Tashjian $ // // $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" CWDMVideoCaptureStream::CWDMVideoCaptureStream(PHW_STREAM_OBJECT pStreamObject, CWDMVideoDecoder * pCWDMVideoDecoder, PKSDATAFORMAT pKSDataFormat, PUINT puiErrorCode) : CWDMCaptureStream(pStreamObject, pCWDMVideoDecoder, puiErrorCode) { m_stateChange = Initializing; DBGTRACE(("CWDMVideoCaptureStream::Startup()\n")); PKS_DATAFORMAT_VIDEOINFOHEADER pVideoInfoHeader = (PKS_DATAFORMAT_VIDEOINFOHEADER) pKSDataFormat; PKS_VIDEOINFOHEADER pVideoInfoHdrRequested = &pVideoInfoHeader->VideoInfoHeader; // Since the VIDEOINFOHEADER is of potentially variable size // allocate memory for it UINT nSize = KS_SIZE_VIDEOHEADER(pVideoInfoHdrRequested); DBGINFO(("pVideoInfoHdrRequested=%x\n", pVideoInfoHdrRequested)); DBGINFO(("KS_VIDEOINFOHEADER size=%d\n", nSize)); DBGINFO(("Width=%d Height=%d BitCount=%d\n", pVideoInfoHdrRequested->bmiHeader.biWidth, pVideoInfoHdrRequested->bmiHeader.biHeight, pVideoInfoHdrRequested->bmiHeader.biBitCount)); DBGINFO(("biSizeImage=%d\n", pVideoInfoHdrRequested->bmiHeader.biSizeImage)); DBGINFO(("AvgTimePerFrame=%d\n", pVideoInfoHdrRequested->AvgTimePerFrame)); m_pVideoInfoHeader = (PKS_VIDEOINFOHEADER)ExAllocatePool(NonPagedPool, nSize); if (m_pVideoInfoHeader == NULL) { DBGERROR(("ExAllocatePool failed\n")); *puiErrorCode = WDMMINI_ERROR_MEMORYALLOCATION; return; } // Copy the VIDEOINFOHEADER requested to our storage RtlCopyMemory( m_pVideoInfoHeader, pVideoInfoHdrRequested, nSize); MRect t(0, 0, pVideoInfoHdrRequested->bmiHeader.biWidth, pVideoInfoHdrRequested->bmiHeader.biHeight); m_pDevice->SetRect(t); Startup(puiErrorCode); } CWDMVideoCaptureStream::~CWDMVideoCaptureStream() { DBGTRACE(("CWDMVideoCaptureStream::~CWDMVideoCaptureStream()\n")); Shutdown(); if (m_pVideoInfoHeader) { ExFreePool(m_pVideoInfoHeader); m_pVideoInfoHeader = NULL; } } BOOL CWDMVideoCaptureStream::GetCaptureHandle() { int streamNumber = m_pStreamObject->StreamNumber; if (m_hCapture == 0) { DBGTRACE(("Stream %d getting capture handle\n", streamNumber)); DDOPENVPCAPTUREDEVICEIN ddOpenCaptureIn; DDOPENVPCAPTUREDEVICEOUT ddOpenCaptureOut; RtlZeroMemory(&ddOpenCaptureIn, sizeof(ddOpenCaptureIn)); RtlZeroMemory(&ddOpenCaptureOut, sizeof(ddOpenCaptureOut)); ddOpenCaptureIn.hDirectDraw = m_pVideoPort->GetDirectDrawHandle(); ddOpenCaptureIn.hVideoPort = m_pVideoPort->GetVideoPortHandle(); ddOpenCaptureIn.pfnCaptureClose = DirectDrawEventCallback; ddOpenCaptureIn.pContext = this; if ((!ddOpenCaptureIn.hDirectDraw)|| (!ddOpenCaptureIn.hVideoPort)|| (!ddOpenCaptureIn.pfnCaptureClose)|| (!ddOpenCaptureIn.pContext)) { return FALSE; } // Now to get the size, etc RECT rcImage; /* ** HOW BIG IS THE IMAGE REQUESTED (pseudocode follows) ** ** if (IsRectEmpty (&rcTarget) { ** SetRect (&rcImage, 0, 0, ** BITMAPINFOHEADER.biWidth, BITMAPINFOHEADER.biHeight); ** } ** else { ** // Probably rendering to a DirectDraw surface, ** // where biWidth is used to expressed the "stride" ** // in units of pixels (not bytes) of the destination surface. ** // Therefore, use rcTarget to get the actual image size ** ** rcImage = rcTarget; ** } */ if ((m_pVideoInfoHeader->rcTarget.right - m_pVideoInfoHeader->rcTarget.left <= 0) || (m_pVideoInfoHeader->rcTarget.bottom - m_pVideoInfoHeader->rcTarget.top <= 0)) { rcImage.left = rcImage.top = 0; rcImage.right = m_pVideoInfoHeader->bmiHeader.biWidth - 1; rcImage.bottom = m_pVideoInfoHeader->bmiHeader.biHeight - 1; } else { rcImage = m_pVideoInfoHeader->rcTarget; } int xOrigin, yOrigin; m_pDevice->GetVideoSurfaceOrigin(&xOrigin, &yOrigin); ddOpenCaptureIn.dwStartLine = rcImage.top + yOrigin; ddOpenCaptureIn.dwEndLine = rcImage.bottom + yOrigin; // Fail-safe if (ddOpenCaptureIn.dwStartLine > 500) { DBGERROR(("Unexpected capture start line. Using default\n")); ddOpenCaptureIn.dwStartLine = 0; } if (ddOpenCaptureIn.dwEndLine > 500) { DBGERROR(("Unexpected capture end line. Using default\n")); ddOpenCaptureIn.dwEndLine = m_pDevice->GetDecoderHeight() - 1; } DBGINFO(("Video surface: %d, %d\n", ddOpenCaptureIn.dwStartLine, ddOpenCaptureIn.dwEndLine)); ddOpenCaptureIn.dwFlags = DDOPENCAPTURE_VIDEO; // Integer math, so it will throw away fractional part m_everyNFields = min (max ( 1, (ULONG) m_pVideoInfoHeader->AvgTimePerFrame/NTSCFieldDuration), MAXULONG); // Now look at that fractional part. If there was a significant // amount, we'll need to round down to the next nearest // frame rate (i.e., skip additional field) // 'Significant' is currently assumed to be 1 uS. That // is '10' in units of 100ns if ((m_pVideoInfoHeader->AvgTimePerFrame - (NTSCFieldDuration * m_everyNFields)) > 10) { m_everyNFields++; } ddOpenCaptureIn.dwCaptureEveryNFields = m_everyNFields; DBGINFO(("Capturing every %d fields\n", ddOpenCaptureIn.dwCaptureEveryNFields)); DxApi(DD_DXAPI_OPENVPCAPTUREDEVICE, &ddOpenCaptureIn, sizeof(ddOpenCaptureIn), &ddOpenCaptureOut, sizeof(ddOpenCaptureOut)); if (ddOpenCaptureOut.ddRVal != DD_OK) { m_hCapture = 0; DBGERROR(("DD_DXAPI_OPENVPCAPTUREDEVICE failed.\n")); // TRAP(); return FALSE; } else { m_hCapture = ddOpenCaptureOut.hCapture; } } return TRUE; } VOID CWDMVideoCaptureStream::SetFrameInfo(PHW_STREAM_REQUEST_BLOCK pSrb) { int streamNumber = m_pStreamObject->StreamNumber; PSRB_DATA_EXTENSION pSrbExt = (PSRB_DATA_EXTENSION)pSrb->SRBExtension; PKSSTREAM_HEADER pDataPacket = pSrb->CommandData.DataBufferArray; LONGLONG droppedThisTime = 0; PKS_FRAME_INFO pFrameInfo = (PKS_FRAME_INFO) (pDataPacket + 1); m_FrameInfo.dwFrameFlags = 0; m_FrameInfo.ExtendedHeaderSize = pFrameInfo->ExtendedHeaderSize; // Set the discontinuity flag if frames have been previously dropped. if ((m_FrameInfo.PictureNumber + 1) < pSrbExt->ddCapBuffInfo.dwFieldNumber/m_everyNFields) { droppedThisTime = pSrbExt->ddCapBuffInfo.dwFieldNumber/m_everyNFields - (m_FrameInfo.PictureNumber + 1); m_FrameInfo.DropCount += droppedThisTime; pDataPacket->OptionsFlags |= KSSTREAM_HEADER_OPTIONSF_DATADISCONTINUITY; #ifdef DEBUG static int j; DBGPRINTF((" D%d ", droppedThisTime)); if ((++j % 10) == 0) { DBGERROR(("\n")); } #endif } m_FrameInfo.PictureNumber = pSrbExt->ddCapBuffInfo.dwFieldNumber/m_everyNFields; m_FrameInfo.dwFrameFlags |= KS_VIDEO_FLAG_FRAME; *pFrameInfo = (KS_FRAME_INFO)m_FrameInfo; } void CWDMVideoCaptureStream::ResetFrameCounters() { m_FrameInfo.PictureNumber = 0; m_FrameInfo.DropCount = 0; } void CWDMVideoCaptureStream::GetDroppedFrames(PKSPROPERTY_DROPPEDFRAMES_CURRENT_S pDroppedFrames) { pDroppedFrames->PictureNumber = m_FrameInfo.PictureNumber; pDroppedFrames->DropCount = m_FrameInfo.DropCount; pDroppedFrames->AverageFrameSize = m_pVideoInfoHeader->bmiHeader.biSizeImage; }